MCP App Store
by KeenEthics

Overview

AhaSlides is a productivity tool for building and running interactive presentations. It turns a prompt into a ready-to-present deck. Ask ChatGPT to build a deck with live polls, quizzes, word clouds and Q&A, edit slides and themes, create surveys, organise presentations into folders, share them with collaborators, and read back how your audience answered. Who it is for: teams, trainers, facilitators and teachers who run meetings, workshops and training sessions. What it can do: - Create and edit presentations and slides, including quizzes, polls, word clouds and content slides. - Find, read, rename, duplicate, move and delete your presentations and folders. - Create, edit and publish surveys and read a summary of their results. - Read audience responses and live Q&A questions from your sessions. - Manage who can collaborate on a presentation or survey. Limitations: AhaSlides only accesses the presentations, surveys and courses available to the AhaSlides account you connect. Presenting live to an audience happens in AhaSlides itself; each result includes a link to open the presentation in the AhaSlides editor.

Tools

add_collaborators

ChatGPT
Share a presentation or folder. As a side effect, an email invite is sent to each address in collaborators. For surveys use add_survey_collaborators. Args: target_type: "presentation" or "folder". target_id: ID of that presentation or folder. collaborators: Email addresses to invite. account_ids: Existing account IDs to grant access to. invited_role: (Optional) Role to grant (e.g. "editor", "viewer").

add_course_collaborators

ChatGPT
AhaSlides eLearning tool. Share a course with people by email. Owner only. `invitees is [{"email", "role": "editor" | "viewer"}] (role defaults to editor; 1-10 per call). An editor changes content but cannot publish, see learners or share; a viewer only reads. Returns granted, unregistered (no AhaSlides account — not added, ask them to sign up first), skipped (e.g. the owner's own email) and notifications`.

add_lesson_block

ChatGPT
AhaSlides eLearning tool. Add ONE content block to a page of an existing lesson. `page_id comes from get_lesson_tree or from the call that created the page. type MUST be a real aha.* type: an invented one (e.g. paragraph) or aha.page is rejected and NOTHING is written. content must match the type's exact shape — call list_lesson_block_types for all 24 types' shapes, variants and capabilities (agentAuthorable: false types cannot usefully be created here). aha.knowledgeCheck ("add a quiz/question") takes the model-facing shape listed there, expanded server-side. variant is the layout, passed as its OWN argument: inside content it is stored and ignored by the renderer. An unknown variant is rejected with the valid ones named and nothing written; omit it for the type's first. Returns JSON: {"id", "type", "content"}`.

add_lesson_blocks

ChatGPT
AhaSlides eLearning tool. Add SEVERAL content blocks to a lesson in ONE call; entries may target different pages. Prefer this over ``add_lesson_block`` for more than one block: one turn and one set of checks instead of one per block. `blocks is a list of at most 40 {"page_id", "type": "aha.*", "content": {...}, "variant"?}: page_id from get_lesson_tree; type, content and variant exactly as add_lesson_block documents them (shapes: list_lesson_block_types). **Order is the list order**, appended to each page. To position against existing blocks use add_lesson_block or reorder_lesson_blocks. **Validation is all-or-nothing, writing is not.** One bad entry (unknown type, aha.page, unknown variant, ungradeable knowledge check, too many blocks) writes NOTHING and the error names its index. If a storage write then fails partway, earlier blocks stay and the result reports it: retry only the remainder. Returns JSON: {"lesson_id", "blocks_requested", "blocks_created", "blocks": [{"id", "type", "content", "variant"}], "error"}`.

add_lesson_page

ChatGPT
AhaSlides eLearning tool. Add ONE new page, with its content, to an existing lesson. For several pages use `add_lesson_pages. **Pass blocks and you are done in one call.** blocks is add_lesson_blocks' list with page_id left out, at most 40 entries of {"type": "aha.*", "content": {...}, "variant": ...}, following add_lesson_block's rules (knowledge-check shape included) and appended in reading order. after_page_id (from get_lesson_tree) inserts after that page; omit it to append. **A rejected blocks payload creates NOTHING — not even the page**; the error names the index (blocks[2]). If a storage write fails after the page exists, what landed stays and error.index says where it stopped — resend only the remainder, never the whole call. Returns JSON: {"id", "type", "content", "variant", "blocks", "blocks_requested", "blocks_created", "error"}; without blocks the last four are [] / 0 / 0 / null`.

add_lesson_pages

ChatGPT
AhaSlides eLearning tool. Add SEVERAL pages, each with its blocks, to an existing lesson in ONE call. Prefer it over repeated `add_lesson_page: one turn instead of one per page. pages is [{"title", "blocks"?: [{type, content, properties?}]}], appended in order (shapes: list_lesson_block_types). after_page_id places the run after that page; omit it to append. Every page is validated BEFORE the first write, so one bad block writes nothing. A failure DURING the writes stops and reports pages_created — retry only the rest, or you duplicate what landed. Returns JSON: {"lesson_id", "pages_created": [{"id", "title", "blocks": [{"id", "type"}]}], "pages_requested", "failed"?}`.

add_survey_collaborators

ChatGPT
Share a survey with people by email. Only the survey owner can do this. As a side effect, each invitee is notified by email. Emails without an AhaSlides account are returned in unregistered and are NOT added — ask them to sign up first. Limits: up to 10 emails per call, 30 invitees per user per day. Args: survey_id: ID of the survey to share. emails: Email addresses to invite. role: (Optional) "editor" (default) or "viewer", applied to every email.

add_survey_element

ChatGPT
Add one question/element to a survey. Args: survey_id: ID of the survey. element_type: One of: statement, multiple_choice, linear_scale, short_text, long_text, matrix, rating, date, ranking, contact_info, nps. title: (Optional) Element title/question text. description: (Optional) Helper text. required: Whether an answer is required. settings: Type-specific settings, e.g. multiple_choice: {"choices": [{"text": "A"}, {"text": "B"}], "allow_multiple": false} linear_scale: {"min_value": 1, "max_value": 5} statement: {"body": "...", "button_text": "Continue"} matrix: {"rows": [{"text": "Price"}], "columns": [{"text": "Good"}]} rating: {"scale": 5, "icon": "star"} ranking: {"choices": [{"text": "A"}, {"text": "B"}]} contact_info: {"fields": [{"field": "email", "required": true}]} nps: {} (fixed 0-10 scale — nothing to configure) (ids/positions for choices/rows/columns are added for you; contact_info fields are name/email/phone/company, each at most once.) section_id: (Optional) Section to add the element to. position: (Optional) Position within the section.

add_survey_elements

ChatGPT
Add several questions/elements to a survey in one call (1 to 20). Use this to build a survey: one call with every element, in order. Args: survey_id: ID of the survey. elements: List of elements. Each is {"element_type", "title"?, "description"?, "required"?, "settings"?} with the same meaning as add_survey_element. section_id: (Optional) Page to add to. Defaults to the survey's last page; a page is created when the survey has none. Returns: {"created": [...], "created_count", "requested_count", "section_id", "failed": null | {"index", "error"}}. Elements are added in order and the call stops at the first failure, so "failed.index" is the first element that was NOT added.

add_survey_section

ChatGPT
Add a section (page) to a survey. Args: survey_id: ID of the survey. title: (Optional) Section title. description: (Optional) Section description. position: (Optional) Position of the section.

convert_slides_to_content_v2

ChatGPT
Convert legacy content slides into NEW content-v2 slides. Accepts the legacy static types: content (free-form canvas), heading (textSlide) and list (bulletPoints). Each source slide gets a new content-v2 slide inserted directly after it, with layout, text styling, images, shapes and the slide theme (colours, background image) carried over. Source slides are never modified or deleted; delete them with update_slide_properties afterwards if the user wants only the new versions. Prefer this over re-creating the slide with create_slides when the user wants an existing slide upgraded to Content V2. Args: presentation_id: The presentation the slides belong to. slide_ids: Slide ids to convert, in order (at most 50 per call; the rest come back as batch_limit_exceeded). Interactive slides are rejected per slide with code unsupported_slide_type; an empty slide with empty_slide; a wrong id with slide_not_found. Returns: {"success": bool, "message": str, "data": {"converted": [{source_slide_id, new_slide_id, source_type, blocks_in, blocks_out, warnings: [{code, message, block_id}]}], "failed": [{slide_id, code, message}]}} success is true when at least one slide converted; warnings lists lossy steps such as mark_dropped or theme_copy_failed.

create_course

ChatGPT
AhaSlides eLearning tool. Create a new, empty DRAFT course; returns JSON with its `id. Then add lessons with create_lesson and fill them with add_lesson_pages / add_lesson_blocks. The result includes editor_url`, the link to the course editor: share it as-is, never build one.

create_folder

ChatGPT
Create a folder to organise presentations. Args: folder_name: Name of the new folder. parent_folder_id: (Optional) Nest under this folder. Returns: Dict with the created folder.

create_lesson

ChatGPT
AhaSlides eLearning tool. Add an EMPTY lesson at the end of a course — one blank page, no content — as the course editor's "Add lesson" does. Fill it with `add_lesson_blocks on the returned page_id. Returns JSON: {"lesson_id", "title", "page_id"}. On partial_create the lesson exists without its page: add_lesson_page on details.lesson_id, never create it again. The result includes editor_url`, the link to the lesson editor: share it as-is, never build one.

create_presentation

ChatGPT
Create a new AhaSlides presentation. Creates an empty presentation with the given name. After creating, use create_slides to add slides to it. Args: name: Name of the presentation to create (e.g. "Q3 Team Review"). lang: Language code for the presentation (optional, e.g. "en", "vi", "ja"). Returns: Dict with success status and presentation data including the new presentation ID, plus editor_url — the link to open the presentation in the AhaSlides editor. Share editor_url with the user.

create_skill

ChatGPT
Save a personal skill: a plain-text instruction. Limits: title at most 80 characters, body at most 4000, description at most 200; applies_to any of presentation, survey, course. folder_id: a My files folder; none = root.

create_slides

ChatGPT
Create slides in a presentation. Slide types are registered dynamically: list_slide_types names them and load_slide_type_specs gives each type's fields. Each dict needs a 'slide_type' plus that type's fields. Before building or restructuring a deck (two or more new slides), call load_authoring_guide once — it holds the routing, density, interactivity and theme rules this tool relies on. Static slides: prefer content-v2 (its layouts skill holds the templates; grammar only when no layout fits; creative only for effects beyond the layouts' built-in reveals) over the legacy content / listing types, which are a fallback only when content-v2 is absent. Diagrams, word clouds: its 26-diagram; charts: 27-chart; diagram only for swimlanes or edits. Act on any "Design check" lines ("new slide N": Nth of this call; runs checked per call). AhaSlides is interactive: unless the user asks for static-only, weave in polls, quizzes, word clouds, scales and Q&A — about 40% of a deck. Images: search_images or bring your own, rehost with upload_image, and reference the returned URL. Never hot-link a foreign image URL. Every slide dict accepts an optional notes (speaker notes) string. Positioning: insert_after_slide_id places slides after that ID; omitting it appends. Each call inserts at a single position. The 'order' field is not accepted — ordering is derived server-side. Args: slides: List of dicts with 'slide_type' and the type's fields, per load_slide_type_specs. presentation_id: Target presentation ID. insert_after_slide_id: (Optional) Slide ID to insert after. Returns: Dict with created slides including IDs. On a brand-new presentation the empty placeholder poll it starts with is removed after the create, and the message says so.

create_survey

ChatGPT
Create a new survey with one empty page ready for questions. Args: title: Title of the survey. Returns: Dict with the new survey's id (use it for all later calls), section_id, the first page's id, and editor_url, the link to the survey editor: share it as-is, never build one.

delete_folder

ChatGPT
Delete a folder. This is a soft delete — its presentations move to trash and can be recovered. Args: folder_id: ID of the folder to delete.

delete_lesson

ChatGPT
AhaSlides eLearning tool. Delete one lesson of a course with all its pages and blocks. Not undoable: confirm with the user first. `lesson_id must be a lesson of THIS course, top-level or inside a module (get_course_tree); only the lesson is deleted, never its module or the course. Returns JSON: {"id", "deleted"}`.

delete_lesson_block

ChatGPT
AhaSlides eLearning tool. Delete a content block from a lesson. Also deletes a PAGE with everything on it (`delete_lesson_page is the typed form), never the lesson's last page nor the lesson itself (delete_lesson). Not undoable. Returns JSON: {"id", "deleted"}`.

delete_lesson_page

ChatGPT
AhaSlides eLearning tool. Delete one page of a lesson AND every block on it. Not undoable: confirm with the user first. A lesson always keeps at least one page, so its last page is refused (`last_page) — delete its blocks instead. Returns JSON: {"id", "deleted"}`.

delete_presentations

ChatGPT
Delete one or more presentations. This is a soft delete — they move to trash and can be restored with recover_presentations. Args: presentation_ids: IDs of the presentations to delete.

delete_skill

ChatGPT
Delete one of your own skills. Recoverable from trash.

delete_survey_element

ChatGPT
Delete an element/question from a survey. Args: survey_id: ID of the survey. element_id: ID of the element to delete.

delete_survey_section

ChatGPT
Delete a section from a survey. Args: survey_id: ID of the survey. section_id: ID of the section to delete.

duplicate_presentation

ChatGPT
Duplicate a presentation. The copy's name is suffixed automatically. Args: presentation_id: ID of the presentation to copy. Returns: Dict with the new presentation, including editor_url — the link to open the copy in the AhaSlides editor. Share it with the user.

get_course_tree

ChatGPT
AhaSlides eLearning tool. Read an existing course's lessons. Call this before adding another lesson, or whenever you need a lesson's id to pass to the lesson tools (`get_lesson_tree, add_lesson_block, ...). Returns JSON: {"course_id", "title", "lessons": [{"id", "title", "module_id"}], "modules": [{"id", "title", "lesson_ids"}]}. lessons is one flat list in course order, including lessons inside modules; module_id is null for a top-level lesson. The course and each lesson carry editor_url`, the link to the course or lesson editor: share it as-is, never build one.

get_lesson_tree

ChatGPT
AhaSlides eLearning tool. Read an existing lesson's pages and content blocks, in on-page order. Call it BEFORE modifying a lesson: `update_lesson_block replaces content wholesale, so you need the block's full current content. Do not call it after a write to confirm — every write returns what it stored. Returns JSON: {"lesson_id", "title", "pages": [{"id", "title", "blocks": [{"id", "type", "variant", "content"}]}]}. variant is the block's layout ("" if never set), the value add_lesson_block` accepts.

get_presentation_detail

ChatGPT
Get complete presentation detail including all slides, theme, and active slide. Returns comprehensive information about a presentation: - presentation_name: The presentation's title - slides_overview: Compact list of all slides with type, title, ID, and key settings - slides_detailed: Full markdown breakdown of each slide's content and configuration - slides_with_id_and_order: ID and order for each slide (useful for positioning operations) - theme_id / theme_name: Current theme applied to the presentation - current_active_slide_id: Which slide is currently active in a live session - editor_url: Link to open the presentation in the AhaSlides editor — share this with the user Provides the presentation structure typically needed before making changes. Args: presentation_id: ID of the presentation to fetch. include_media: Also return slide image and YouTube URLs. Returns: Dict with presentation detail, slides overview, and theme information.

get_presentation_settings

ChatGPT
Read a presentation's settings (read-only): API key, value, and the label users see. Take this snapshot before changing any setting, so you can restore the old value. Match what the user says to the label, then use the key. Today the only setting you can change is isModerationMode, via update_presentation_settings. Requires permission to present. Args: presentation_id: ID of the presentation. Returns: settings, a list of {key, label, value[, meaning]}.

get_skill

ChatGPT
Read one skill with its text. skill_id from list_skills.

get_skill_for_intent

ChatGPT
Read the built-in skill (any role) with this intent: {"skill": <as get_skill>}, or {"skill": null}.

get_survey

ChatGPT
Read a survey's full structure (sections + elements with their ids). Args: survey_id: ID of the survey. Returns: The survey plus editor_url, the link to the survey editor: share it as-is, never build one.

get_survey_results_summary

ChatGPT
Get a response/results summary for a survey. Args: survey_id: ID of the survey.

get_themes

ChatGPT
Get all available themes (official, custom, and team-shared). Returns three categories of themes: - official_themes: Built-in themes available to all users - custom_themes: Themes created by the current user - shared_themes: Themes shared by team members Each theme includes: - id: Theme ID (use this with update_presentation_theme) - themeName: Display name of the theme - textColour: Text color hex code - baseColour: Background color hex code The theme id returned here is what update_presentation_theme accepts to apply a theme to a presentation. Returns: Dict with official_themes, custom_themes, and shared_themes lists.

insight_publish

ChatGPT
Mint the share link for an insight, and get back a URL you can hand over. Idempotent: publishing an already-published insight returns the same link rather than minting a second one, so a token cannot be orphaned by calling this twice. The link needs no login — the token IS the permission — and it re-runs the pinned queries each time it is opened, so the numbers stay current. Say that to the user before sharing it. Writing never publishes -- there is no flag for it, and no publishError to retry: this tool is the only way an insight becomes shareable. Call it when the person asks to share, send, or get a link -- not because an insight is finished and a link seems tidy. Args: report: reportId of the insight to publish.

insight_query

ChatGPT
Validate, scope and PIN SELECTs to an insight. Returns ids, never rows. THE QUERY IS THE FINDING. You never see the rows — a pinned query is re-run when someone opens the insight, so a value read into prose is true today and wrong after the next session. Put the finding IN the SQL (ORDER BY, LIMIT, a computed rate) and let a stat, chart or table block recompute it. One query per thing shown. Send EVERY query the insight needs in one call. Each is validated on its own, so a mistake costs one query rather than the batch: the result lists what pinned and names each casualty with its reason in failed. Call insight_schema first. A rejection here names the valid alternatives — read it and retry rather than guessing a column. STATE: the result carries the reportId every query landed on. Hold it and pass it back as report on later calls — this server remembers nothing between calls; the insight lives in the report service, keyed to you. Args: queries: A LIST of {"sql": "...", "label": "..."}. report: (Optional) EITHER a reportId from an earlier call, to pin onto that insight, OR — on a first call, when you have no id yet — a short key unique to this piece of work, such as "q3-course-review-2026-09-25". Upstream tells them apart by shape: a UUID is an id, anything else is an idempotency key, and the same key always resolves to the same insight — reusing a key from earlier work returns that earlier insight. Passing a key on the FIRST call is what makes that call safe to retry; omitting report entirely mints a new insight every time, so a timeout there cannot be retried without risking a duplicate you have no id to find.

insight_schema

ChatGPT
The warehouse tables an insight can query, and how much data you own. START HERE, with NO argument. The result's scope says what the caller actually has, per dataset — presentations, and courses/lessons. A count of ZERO is not an obstacle to route around: it IS the answer to every question about that dataset, and this is the only place you can learn it, because a pinned query never returns rows to you. Report the zero rather than presenting it as a finding about activity. table takes SEVERAL table names, comma-separated ("fact_answers2,dim_questions,dim_sessions"), and returns their columns and gotchas. Ask for every table the insight touches in ONE call — a round trip is the expensive unit here. The result also carries the accepted reportTheme keys for insight_write. Read them from here rather than remembering them: they are generated from the validator's own key set, so they cannot drift from what is actually accepted. This REPLACES the deprecated query_user_data / query_presentation_data tools, which see presentation data only and cannot produce a shareable result. Args: table: (Optional) Comma-separated table names to describe. Omit for the table list plus your scope.

insight_write

ChatGPT
Create or edit an insight and write its body. Pinned queries are untouched. Omit report to create one (needs title); pass a reportId to edit. Only the fields you pass change. Charts and tables render FROM THE PINNED QUERY — reference a queryId from insight_query, never paste values into the body. Everything is validated before anything is stored, and the result's stored counts what landed by block and chart type: that is your confirmation it validated. blocks = {"version": 1, "blocks": [...]}, each one of: {"type":"heading","text":"...","level":2} {"type":"text","md":"Markdown. Inline HTML is not rendered."} {"type":"divider"} {"type":"image","src":"https://...","alt":"...","width":160,"align":"left"} {"type":"stat","query":"q_","column":"col","label":"...","row":0} {"type":"chart","query":"q_","chart":"bar","x":"col","y":["col"],"title":null,"limit":50} {"type":"table","query":"q_","columns":["a","b"],"limit":50} {"type":"row","columns":[{"width":3,"blocks":[...]},{"width":9,"blocks":[...]}]} {"type":"tabs","tabs":[{"label":"Overview","blocks":[...]}]} chart: bar hbar line area pie donut scatter row: 2-4 columns. width is a span of a 12-column grid; set one on every column totalling 12, or on none for equal. A tab may hold rows; a row may not hold tabs. Args: report: (Optional) A reportId to edit. An ID ONLY — unlike insight_query, this takes no idempotency key: anything that is not a UUID is rejected as not a valid id. Omit to create a new insight (needs title), which mints a fresh one every call and so cannot be safely repeated after a timeout. The usual flow avoids that anyway: pin a query first, then write the body with the reportId that comes back. title: Names the insight. Required when creating. blocks: The body, in the shape above. theme: (Optional) Colours and font. insight_schema returns the accepted keys under reportTheme; keys that did not apply come back as themeIgnored. This does NOT share. url comes back only when the insight already has a link; none is created here. Use insight_publish, and only when the person asks — the link needs no login, so anyone holding it sees the data.

list_collaborators

ChatGPT
List the people a presentation or folder is shared with. For surveys use list_survey_collaborators. Args: target_type: "presentation" or "folder". target_id: ID of that presentation or folder.

list_course_collaborators

ChatGPT
AhaSlides eLearning tool. List the people a course is shared with: each one's `user_id, email, name, role (owner/editor/viewer) and is_owner. Use the user_id with update_course_collaborator_role or remove_course_collaborator`.

list_courses

ChatGPT
AhaSlides eLearning tool. List the caller's COURSES (id, title, draft/published), newest first. Not lesson ids — those come from `list_lessons. status="published" narrows to courses learners can already open. Returns JSON with items and next_cursor. Each course carries editor_url`, the link to the course editor: share it as-is, never build one.

list_folders

ChatGPT
List the user's folders as a full nested tree, or search them by name. Args: query: (Optional) Text to search for in folder names. Omit for the tree.

list_lesson_block_types

ChatGPT
AhaSlides eLearning tool. The full `aha.* block-type catalogue: each type's purpose, content shape, layout variants, interactive/scored/tracksCompletion capabilities, and whether it is agentAuthorable (if not, unauthorableReason says why — usually a media URL or presentation). Call it while PLANNING a lesson, before writing blocks. Returns JSON: [{"type", "label", "summary", "agentAuthorable", "unauthorableReason"?, "contentShape", "variants", "capabilities"}]`.

list_lessons

ChatGPT
AhaSlides eLearning tool. List the caller's LESSONS (id, title, draft/published status): where a `lesson_id for get_lesson_tree, add_lesson_page, add_lesson_block and the other lesson tools comes from. Returns JSON with items and next_cursor`.

list_presentations

ChatGPT
List or search the user's presentations (paginated). Args: text_search: (Optional) Filter by title/metadata text. limit: Page size (default 20). page: 1-based page number. Returns: Dict with the matching presentations.

list_qna_questions

ChatGPT
Read a presentation's audience Q&A questions live, as they arrive. Use this to help a presenter moderate Q&A during a session: group questions by topic, spot duplicates, and suggest which to answer next. Data is live (a few seconds old at most) — unlike query_presentation_data, which reads the warehouse and has no Q&A. Polling: the first call (no after_id) lists every question. Pass the returned next_after_id on the next call to list only questions that arrived since. If truncated is true, call again with next_after_id to page through the rest. counts and top_open always cover the whole Q&A, so the current ranking is in every response. A listed question's votes, answered or dismissed state can change later — call without after_id to refresh everything. Each question has: id, text, votes, answered, pinned, status ('approved' | 'pending' | 'dismissed' — 'pending' only exists when moderation_on is true and means the audience can't see it yet), author, created_at. Requires permission to present the presentation. Args: presentation_id: The presentation being presented (the id in its editor URL). after_id: (Optional) A previous call's next_after_id. include_answered: (Optional) List questions marked answered. Default true. include_dismissed: (Optional) List dismissed questions. Default false. limit: (Optional) Max questions listed per call, oldest first. Default 200, max 500. Returns: Dict with moderation_on, counts, top_open (up to 10 unanswered questions, pinned first, then by votes), questions, truncated and next_after_id.

list_skills

ChatGPT
List your skills and the built-in recipes. Returns titles and descriptions only; call get_skill for the text.

list_slide_types

ChatGPT
List every available slide type with a one-line description. Covers plugin types that are registered dynamically and so are not enumerated in this server's static docstrings. The full schema for a given type is available from load_slide_type_specs. Returns: markdown bullet list of slide_type: short description.

list_survey_collaborators

ChatGPT
List the people a survey is shared with (user_id, email, name, role, is_owner). Args: survey_id: ID of the survey.

list_workspace_items

ChatGPT
Browse the user's own files one folder at a time: sub-folders plus presentations, surveys and courses, newest first. No folder_id = the root, with recent items from every folder. kinds: any of presentation, survey, course; ["folder"] alone. Page with cursor = next_cursor, other arguments unchanged.

load_authoring_guide

ChatGPT
Load the deck-quality rules the AhaSlides Slides Agent authors by. Call this ONCE before building, expanding or restructuring a deck (two or more new slides). It covers how to route each slide by its role (content-v2 for covers, agendas, bullets, stats, quotes, and its 26-diagram / 27-chart for diagrams and charts; interactive types as engagement checkpoints), per-slide density limits, the interactive ratio, the readiness check, and how to match a theme. Static guidance, no user data — needs no token. Returns: markdown guidelines, phrased for this server's tool names.

load_course_authoring_guide

ChatGPT
Load the rules for building a good AhaSlides course or lesson. Call this ONCE before building or restructuring a course or a lesson. Covers how to use the course and lesson tools, then the course and lesson standards. task "convert" adds the rules for converting a presentation.

load_powerpoint_addin_guide

ChatGPT
Call this BEFORE generating any PowerPoint / .pptx file (slide deck, presentation file) that should contain live interactive AhaSlides slides — quizzes, polls, word clouds, Q&A, audience participation. Returns the AhaSlides PowerPoint add-in embed contract, the end-to-end workflow, and a copy-pasteable Python injector that turns blank slides of a pptx you built into live, embedded add-in slides bound to slides you created here. Static guidance, no user data — needs no token. Returns: markdown guide with the injector script inline.

load_slide_skills

ChatGPT
Load deep reference docs ("skills") for a single slide type in one call. For a spec's "Available skills" footer. Several ids per call; section refs "<skill>#index" (catalog) and "<skill>#<id>" (one section plus the skill's shared rules) load part of a skill. content-v2: layouts (templates) whole, or layouts#index then layouts#<id>; grammar only when no layout fits; creative only for effects beyond the layouts' built-in reveals. Args: slide_type: The slide_type that owns the skills (e.g. "content-v2"). skill_ids: Skill ids or section refs (e.g. "layouts#index"). Returns: markdown reference docs for the requested skills.

load_slide_type_specs

ChatGPT
Load full specs (required fields, examples, JSON schema) for one or more slide types. Accepts multiple slide types in one call. Names are case-sensitive and match those returned by list_slide_types. Args: slide_types: List of exact slide_type names (case-sensitive). detail: "compact" drops the parts a spec marks full-context only. Returns: markdown spec per type, separated by ---.

load_survey_authoring_guide

ChatGPT
Load the rules for building a good AhaSlides survey. Call this ONCE before building or restructuring a survey. Covers the workflow, the shape of a good survey, every element type with its settings, and what these tools cannot do. Static guidance, no user data.

load_workflow_skill

ChatGPT
Load the built-in workflow that matches what the user typed, before you act on it. Call it once, first, with the intent of the line that fits best; skip it when the message already carries an applied skill or no line fits. Returns {"skill": {id, title, body, ...}} or {"skill": null}; null means carry on without it. The product's authoring guide still applies. Intents: - course_from_document: Use when the user supplies a document, such as a manual, a policy, a handbook or notes, and wants a course from it. Not for a course from a deck or from survey results. - course_from_survey: Use when the user wants a course that targets the gaps a needs assessment or feedback survey found. Not for a survey about a course, or for a results deck. - improve_course: Use when the user asks to improve, fix or extend the open course or lesson, or to add scored assessments to it. Not for building a new course or converting a deck. - create_presentation: Use when the user asks for a new deck from a topic or a short brief. Not for a deck built from a document, a survey or a course, or for changing an existing deck. - improve_presentation: Use when the user asks to improve, polish, shorten or make the open deck more engaging. Not for building a new deck, or for turning a deck into a survey or a course. - presentation_from_course: Use when the user wants a live session for a course: a kick-off before learners start it, or a recap after they finish. Not for turning a deck into a course. - presentation_from_document: Use when the user supplies a document, notes, an article or a file and wants a deck from it. Not for a deck from a survey or a course, or from a topic alone. - presentation_from_survey: Use when the user wants a deck from a survey: a results deck that presents its answers, or its questions turned into live polls. Not for a survey made from a deck. - create_survey: Use when the user asks for a new survey from a topic or a goal. Not for a survey built from a document, a deck or a course, or for changing an existing survey. - improve_survey: Use when the user asks to improve, shorten, clean up or check the open survey. Not for building a new survey, or for turning a survey into a deck or a course. - survey_from_course: Use when the user wants a survey for a course: an evaluation after learners finish it, or a needs check before the training. Not for a course built from survey results. - survey_from_document: Use when the user supplies a document, such as a proposal, a policy, a report or a questionnaire, and wants a survey from it. Not for a survey from a deck or a course. - survey_from_presentation: Use when the user wants a survey from a deck: feedback after the session, or the deck's questions as a self-paced survey. Not for a results deck from a survey.

moderate_qna_questions

ChatGPT
Approve, dismiss or reset audience questions (Q&A moderation must be on). Judge against the presenter's rules; by default dismiss off-topic, abusive, spam or advertising questions and ones exposing personal data. When unsure, leave it pending: an approved question shows to the audience at once. 'reset' puts a question back to pending. A failed item does not stop the rest. Requires permission to present. Args: presentation_id: The presentation being presented. decisions: Items of {question_id, action}. Returns: results, one {question_id, ok, status | error} per decision.

move_lesson_block

ChatGPT
AhaSlides eLearning tool. Move a content block to another page of the SAME lesson (or elsewhere on its own page), keeping its content and id. Placed right after `after_block_id (a block already on to_page_id), or at the end of that page when omitted; for first place, move it then reorder_lesson_blocks. Returns JSON: {"id", "page_id", "after_block_id"}`.

move_presentations_to_folder

ChatGPT
Move presentations into a folder. Args: presentation_ids: IDs of presentations to move. folder_id: Destination folder ID.

move_slide

ChatGPT
Move a slide to a different position in the presentation. Positioning: - insert_after_slide_id is the ID of an existing slide; the moved slide lands immediately after it. - Omitting insert_after_slide_id moves the slide to the end. - Positioning is expressed with slide IDs, not numeric positions. - Each call moves a single slide. Args: slide_id: ID of the slide to move. presentation_id: ID of the presentation. insert_after_slide_id: (Optional) ID of slide to move after. Omit to move to end. Example - Move slide C after slide A: move_slide(slide_id=slide_c_id, presentation_id=123, insert_after_slide_id=slide_a_id) Returns: Dict with update result and status.

publish_survey

ChatGPT
Publish a survey so it can accept responses (runs backend pre-publish validation). Args: survey_id: ID of the survey to publish.

query_presentation_data

ChatGPT
DEPRECATED — use insight_schema then insight_query instead. Prefer the insight tools for any new request: they also cover courses and lessons, and they produce a shareable link that re-runs its queries rather than rows that are stale the moment they are printed. Use this tool only to finish a flow that already started here. Execute SQL queries in parallel to analyze a specific presentation's audience responses. TABLE: presentation_session_data (auto-filtered to given presentation_id) COLUMNS: id (bigint), slide_id, participant_id, createdat (timestamp), correct (bool, quiz only), is_partially_correct (bool), answer_time_seconds (int), answer_timeout (bool), submitted_answer_text, presentation_title, slide_title, slide_order (int), slide_type, name, email, presentation_id, user_id SLIDE TYPES: Quiz: 'Pick Answer','Short Answer','Match Pairs','Correct Order','Categorise' Interactive: 'Poll','Open Ended','Scale','Brainstorm','Word Cloud' SQL: Query presentation_session_data. CTEs supported. All queries run in parallel. SCOPING: results are automatically limited to the given presentation_id, so a presentation_id filter is unnecessary. Only presentation_session_data is queryable. Example: sqls=["SELECT COUNT(DISTINCT participant_id) as total FROM presentation_session_data", "SELECT slide_title, COUNT(*) as n FROM presentation_session_data GROUP BY slide_title"] Args: sqls: List of SQL queries using presentation_session_data. presentation_id: Presentation to analyze. Returns: List of dicts, one per query, in list-oriented format.

query_user_data

ChatGPT
DEPRECATED — use insight_schema then insight_query instead. Prefer the insight tools for any new request: they also cover courses and lessons, and they produce a shareable link that re-runs its queries rather than rows that are stale the moment they are printed. Use this tool only to finish a flow that already started here. Query all presentations and audience responses for the logged-in user via SQL. DATA MODEL: User -> Presentations (templates) -> Sessions (live events) -> Participants -> Answers. presentation_id = reusable template; session_id = specific live instance. TABLE: user_presentations_data (auto-filtered to logged-in user) COLUMNS: id (bigint), slide_id, participant_id, createdat (timestamp), correct (bool, quiz only), is_partially_correct (bool), answer_time_seconds (int), answer_timeout (bool), submitted_answer_text, presentation_title, slide_title, slide_order (int), slide_type, name, email, presentation_id, session_id, session_hosted_date (timestamp), user_id SLIDE TYPES: Quiz: 'Pick Answer','Short Answer','Match Pairs','Correct Order','Categorise' Interactive: 'Poll','Open Ended','Scale','Brainstorm','Word Cloud' SQL: Write queries against user_presentations_data. CTEs supported: WITH tmp AS (SELECT * FROM user_presentations_data WHERE ...) SELECT ... SCOPING: results are automatically limited to the logged-in user, so a user_id filter is unnecessary. Only user_presentations_data is queryable. Example: SELECT presentation_title, COUNT(DISTINCT session_id) as times_presented, COUNT(DISTINCT participant_id) as participants FROM user_presentations_data GROUP BY presentation_title Args: sql: SQL query using user_presentations_data table. Returns: Dict with query results in list-oriented format.

recover_presentations

ChatGPT
Restore presentations from trash. Args: presentation_ids: IDs of the presentations to recover.

remove_collaborators

ChatGPT
Stop sharing a presentation or folder with people. For surveys use remove_survey_collaborator. Args: target_type: "presentation" or "folder". target_id: ID of that presentation or folder. collaborators: Email addresses to remove. account_ids: Account IDs to remove.

remove_course_collaborator

ChatGPT
AhaSlides eLearning tool. Stop sharing a course with one collaborator; they lose access at once. Owner only. `user_id comes from list_course_collaborators`; the owner cannot be removed.

remove_survey_collaborator

ChatGPT
Stop sharing a survey with a collaborator. Only the survey owner can do this. Args: survey_id: ID of the survey. user_id: Collaborator's user_id (from list_survey_collaborators). The owner cannot be removed.

rename_folder

ChatGPT
Rename a folder. Args: folder_id: ID of the folder to rename. folder_name: New name.

rename_lesson

ChatGPT
AhaSlides eLearning tool. Retitle an existing lesson, standalone or nested in a course; pages, blocks and publish status are untouched. An editor-created course starts with a placeholder "First lesson": rename and fill it rather than adding a second lesson beside it.

rename_presentation

ChatGPT
Rename a presentation. Args: presentation_id: ID of the presentation. name: New title.

reorder_lesson_blocks

ChatGPT
AhaSlides eLearning tool. Reorder the content blocks on a page. `block_ids must list EVERY block currently on page_id (from get_lesson_tree), in the new order you want — the same set of ids, just reordered. It is a reorder only: you cannot add, remove, or move a block to a different page with this tool. Returns JSON: {"page_id", "block_ids"}` — the order that was applied.

reorder_lesson_pages

ChatGPT
AhaSlides eLearning tool. Reorder the PAGES of a lesson. `page_ids must list EVERY page in the lesson (from get_lesson_tree) in the new order; use add_lesson_page/delete_lesson_page to add or remove one. reorder_lesson_blocks is for blocks inside one page and answers "block not found" for a lesson id. Returns JSON: {"page_id", "block_ids"}` — the lesson id and the page order applied.

reorder_lessons

ChatGPT
AhaSlides eLearning tool. Change the order of a course's LESSONS. `lesson_ids must list EVERY lesson of ONE parent (the course top level, or a single module's lesson_ids) exactly once in the new order; a partial, unknown or mixed-parent list is refused and nothing moves. Returns JSON: {"course_id", "lesson_ids"}`.

reorder_survey_elements

ChatGPT
Reorder a survey's elements. Args: survey_id: ID of the survey. order: Full list of element ids in the desired order.

search_images

ChatGPT
Search Unsplash for a photo to use on a slide. Use this before building image-led slides (covers, section breaks, content-v2 :::image blocks) instead of leaving placeholders. Pick the result whose description best fits the slide, then pass its image_url to upload_image to get a hosted AhaSlides URL — never put the Unsplash URL straight into a slide. Credit photographer in the speaker notes when present. Args: query: What the photo should show, e.g. "team collaborating at a whiteboard". Specific, visual phrases work best. limit: How many results to return, 1-10 (default 5). Returns: JSON string. On success {"success": true, "images": [{"image_url", "description", "width", "height", "photographer"}]} (fields Unsplash did not provide are omitted); on failure {"success": false, "message": "..."}.

set_course_access

ChatGPT
AhaSlides eLearning tool. Lock a course to assigned learners (`mode="assigned_only"`), or open it to anyone with the link. Locking a LIVE course removes access from people studying it who are not assigned — confirm with the trainer first. Assigning learners is done in the AhaSlides app, not through these tools — confirm the trainer has assigned people before locking a live course.

set_course_published

ChatGPT
AhaSlides eLearning tool. Publish a course to learners (its lessons render with it), or `published=False to return it to draft without deleting anything. A new course is a draft, invisible until set_course_published is called. Managed courses use a fresh revision, or honour expected_revision exactly; conflicts return fresh state without retrying. Successful retries reconcile the current publication. On a publish, relay any warnings` (pages with no blocks, which learners skip; never blocking).

skip_slide_when_presenting

ChatGPT
Toggle whether a slide is skipped during a live presentation. When a slide is marked as skipped, it will not be shown to the audience during a live presentation session, but remains in the presentation editor. Args: slide_id: ID of the slide to update. skip_when_presenting: True to skip the slide during presentation, False to include it. presentation_id: (Optional) The presentation the slide belongs to. When given, the slide must be in that presentation or nothing is changed — a client that pins writes to the open deck passes it so a slide of another deck cannot be toggled from here. Example - Skip a slide: skip_slide_when_presenting(slide_id=123, skip_when_presenting=True, presentation_id=45) Returns: Dict with update result and status.

update_course

ChatGPT
AhaSlides eLearning tool. Retitle a course, set its description and/or its cover image. Pass whichever you mean. An editor-created course starts as "Untitled course" with no description: name it for what it teaches and describe it for learners. Landscape 16:9 suits best; a portrait image is shown whole, not cropped. `"" removes it. Publish status is set_course_published, not this. cover takes a plain https URL: a search_images result, or the url from upload_image(destination="elearning")`.

update_course_collaborator_role

ChatGPT
AhaSlides eLearning tool. Change a collaborator's role to "editor" or "viewer". Owner only. `user_id comes from list_course_collaborators`; the owner's role cannot change.

update_lesson_block

ChatGPT
AhaSlides eLearning tool. Replace a content block's content and/or change its layout `variant. content REPLACES the stored content WHOLESALE, never merged: read the block with get_lesson_tree and send the FULL object with only your change — a partial object destroys every other field. aha.knowledgeCheck is the exception: send the model-facing shape (format, prompt, options, correct as 0-based indices, acceptedAnswers, pairs, explanation), NOT the stored shape (options[].id, correctId, correctIds, pairs[].id). Resend the whole question with your change, e.g. every option text plus the possibly shifted correct; ids are regenerated and any you send are ignored. An ungradeable result is rejected and NOTHING is written. variant is the only way to change a layout; an unknown one is rejected and nothing written. To change only the layout send variant alone, without content. Sending neither is an error. Returns JSON: {"id", "type", "content", "variant"}`.

update_lesson_page

ChatGPT
AhaSlides eLearning tool. Retitle one page of a lesson; its blocks are untouched. `page_id from get_lesson_tree. A lesson's first page often starts untitled. Returns JSON: {"id", "type", "content", "variant"}`.

update_presentation_settings

ChatGPT
Change presentation settings. Today ONLY Q&A moderation (isModerationMode) can be changed. Call get_presentation_settings first for the keys and current values. Any other key is refused and nothing is changed. Turning moderation ON hides every question with no decision yet from the audience at once, so confirm with the presenter first when mid-session. OFF shows them again. Needs a plan with Q&A moderation. Requires permission to edit. Args: presentation_id: The presentation to change. settings: Setting key to new value, e.g. {"isModerationMode": true}. Returns: changed, unchanged, and affected_questions (hidden or revealed) when moderation changed.

update_presentation_theme

ChatGPT
Apply a theme to a presentation by theme ID. Changes the visual theme of the entire presentation including background, text colors, and styling. Valid theme IDs are those returned by get_themes. Args: presentation_id: ID of the presentation to update. theme_id: ID of the theme to apply (obtained from get_themes). Returns: Dict with success status and updated theme data.

update_skill

ChatGPT
Edit one of your own skills. Only the fields you give change. Built-in recipes cannot be changed. folder_id moves it; 0 = root.

update_slide_content

ChatGPT
Update the content of existing slides. Args: slides: List of dicts. Each MUST include id (int), slide_type (str), and all required fields for that type. presentation_id: ID of the presentation containing the slides. Schemas are identical to create_slides (any type from list_slide_types), with 'id' added to each dict. Act on any "Design check" lines. Example: [{"id": 123, "slide_type": "content", "heading": "New Title", "paragraphs": ["Updated text"]}] Returns: Dict with update result and status.

update_slide_properties

ChatGPT
Update slide properties (deletion, quiz config, display settings) without changing content. Args: slides: List of dicts. Each needs id (int) plus ONLY the properties to change. Do NOT send type or slideType: the slide's real type is filled in for you, and anything sent for them is ignored. A slide's type cannot be changed here; recreate the slide instead. presentation_id: ID of the presentation. Properties: All slides: deleted (bool) Quiz slides: minPoint, maxPoint, timeToAnswer (int), fastAnswerGetMorePoint (bool) Poll, scale, word cloud, open ended: hasTimeLimit (bool), timeToAnswer (int), hideResult (bool), stopSubmission (bool) Poll: showPercentage, addCorrectOption, multipleChoice (bool), limitChoice (int), typeChart ("barChart"|"donutChart"|"pieChart") Brainstorm: limitChoice (int) Word cloud: entriesPerParticipant (int) Open ended: layout ("grid"|"oneByOne"), imageSubmission (bool) Spinner wheel: metadata.spinningDuration (int, max 1200), metadata.autoFillParticipantName (bool) Use move_slide to reorder; order sent here is ignored. Examples: [{"id": 321, "deleted": true}] [{"id": 555, "minPoint": 10, "maxPoint": 100, "timeToAnswer": 30}] [{"id": 556, "timeToAnswer": 60}, {"id": 557, "timeToAnswer": 60}] Returns: Dict with update result and status.

update_survey

ChatGPT
Update a survey's title, description, or settings. Only provided fields change. Args: survey_id: ID of the survey. title: (Optional) New title. description: (Optional) New description. settings: (Optional) Survey-level settings object.

update_survey_collaborator_role

ChatGPT
Change a survey collaborator's role. Only the survey owner can do this. Args: survey_id: ID of the survey. user_id: Collaborator's user_id (from list_survey_collaborators). role: "editor" or "viewer". The owner's role cannot be changed.

update_survey_element

ChatGPT
Update an existing survey element. Only provided fields change. Args: survey_id: ID of the survey. element_id: ID of the element to update. title: (Optional) New title. description: (Optional) New description. required: (Optional) Whether an answer is required. element_type: (Optional) Convert to a different supported type. settings: (Optional) Type-specific settings (see add_survey_element).

update_survey_section

ChatGPT
Update a survey section's title, description, or position. Args: survey_id: ID of the survey. section_id: ID of the section to update. title: (Optional) New title. description: (Optional) New description. position: (Optional) New position.

upload_image

ChatGPT
Upload an image to AhaSlides and get back a hosted URL. Use this to bring your own imagery into presentations or eLearning — images you generated, found, or were given. Always upload external images with this tool instead of hot-linking foreign URLs (foreign links break or get blocked by the presentation renderer). destination decides where it is stored, and the URLs are NOT interchangeable: "slides" (default): a signed AhaSlides CDN link for any slide image field or a content-v2 :::image DSL block. It EXPIRES — never put it in an eLearning lesson or course. "elearning": a permanent URL for an eLearning image block's asset or a course cover. PNG, JPEG, WebP or GIF only. Provide exactly ONE of: image_url: Public https URL of the image. It is fetched server-side (no redirects, must return an image/* content type, max 10MB). image_base64: Base64-encoded image bytes (max 10MB decoded). Prefer this for small assets; prefer image_url for anything large. Args: image_url: Public https image URL to fetch and rehost. image_base64: Base64-encoded image data. filename: Optional filename hint, e.g. "hero.png" — sets the stored extension/content type; defaults to image.png for base64 input. destination: "slides" (default) or "elearning" — see above. Returns: Dict with success and url (plus key, the S3 object key, for slides).

wait_for_qna_questions

ChatGPT
Wait for new audience questions to moderate (Q&A moderation must be on). Returns within about 2 seconds of a new PENDING question, or empty after timeout_seconds (1 to 30). Loop: list_qna_questions once to catch up, then call this with the previous next_after_id, judge the questions, and send the decisions to moderate_qna_questions. With moderation off it returns at once. Requires permission to present. Args: presentation_id: The presentation being presented. after_id: (Optional) Previous call's next_after_id. timeout_seconds: (Optional) Longest wait. Default 10. Returns: moderation_on, questions (id, text, author, votes, created_at), next_after_id, pending_count.

Capabilities

Writes

Example Prompts

Click any prompt to copy it.

Similar Apps