MCP App Store
by KeenEthics

Overview

Omni lets users work with their organization's governed business intelligence data from ChatGPT. The app can list available Omni models, select the best topic for a question, generate and run a single analytical query, start Omni's full AI assistant for deeper multi-step analysis, check the assistant job status, and search Omni documentation.

Tools

askOmni

ChatGPT
Starts the full Omni AI agent on an open-ended or multi-step analytical question and returns immediately with a 'jobId' — it does NOT wait for or return the answer, which is retrieved separately once the job finishes. Use this (not getData) for anything needing planning, several queries, or a reasoned written answer: deep analysis ("what's driving the revenue drop"), investigations ("investigate churn last quarter"), building dashboards and reports, creating visualizations and forecasts, and editing the semantic model. The job runs asynchronously and can take minutes; the response carries 'jobId', 'conversationId', and status:"submitted". Poll checkStatus with the jobId for progress and the answer. To ask a follow-up in the same thread, pass the returned conversationId back in. If modelId was not configured via headers you must pass it. topicName is optional — omit it to let the agent pick.

cancelJob

ChatGPT
Stops a job started by askOmni. Pass its jobId. Call this when the user asks you to stop the job or says they no longer want its work — stopping your checkStatus polling does not stop the job, which keeps running and can still create or change content. Do not cancel just because a job is slow; long runs are normal. The result's 'status' says what happened and is not always "cancelled": "too_late" means the job was already delivering its result, and "complete" or "failed" mean it had already ended. Cancelling marks the job cancelled; the agent stops when it next checks, and the step it is on is neither interrupted nor undone, so an edit it had started or was about to make can still land after this call returns. Follow the result's 'instructions' when you tell the user what happened. Repeating the call is safe.

checkDashboardDownload

ChatGPT
Polls a dashboard download started by startDashboardDownload. Returns the job's status — "in_progress" while it renders, "complete" once the render finished, or "error" with the reason (format is omitted on error) — plus when it was created. "complete" does not mean every tile made it: a tile whose query failed renders empty without changing the status, so say the render may be missing tiles rather than asserting it is whole. A render usually takes seconds to a couple of minutes depending on the dashboard's queries, so wait a few seconds between polls. Once complete, call fetchDashboardDownload with the same identifier and jobId to get the file. The job belongs to the user who started it, so a jobId started as another user is not found.

checkStatus

ChatGPT
Checks on a job started by askOmni and returns quickly. Pass the jobId. While the agent is still working it returns { status: "running", state, progress } — progress.message is what it's doing right now (e.g. "Generating 3 queries"), and the result includes an 'instructions' field telling you what to relay to the user (and to stay quiet when the step is unchanged). Once it's done it returns the full answer: the final markdown 'message', the 'topic', an 'omniChatUrl' (always show it to the user), the 'conversationId' (pass back to askOmni for a follow-up), and a compact 'actions' list. An action that created or edited an Omni app carries the saved document's 'appIdentifier' and 'appTitle'; when the result includes an 'instructions' field about that app, follow it. A failed job returns an error; a cancelled job returns status:"cancelled". To stop a job the user no longer wants, call cancelJob; stopping your polling leaves it running. This is a fast status check — call it again whenever you want a fresh update; you decide how often to poll until it reaches a terminal result. Agentic jobs routinely run for several minutes; that is normal, not a failure — keep polling and don't give up (or tell the user it failed) just because it's still running after a few minutes.

fetchDashboardDownload

ChatGPT
Returns the file a completed dashboard download produced — the job from startDashboardDownload once checkDashboardDownload reports it "complete" — after a text block with its size: a png as an image you can look at, a pdf as an embedded application/pdf resource. A pdf up to 30 MB and a png up to 10 MB come back; past that the response says what to do instead (a pdf render for an oversized png). Calling this before the job completes is not an error state to retry blindly: it reports that the job is still in progress, so poll checkDashboardDownload first.

get-dashboard-import-job-status

ChatGPT
Checks on a dashboard import started by import-claude-dashboard-from-url. Returns { status: "processing", progress } while the queries are checked and the app is built, { status: "done", dashboard_url, snapshot_only, unverified, drifted } once the app exists (snapshot_only names the sources the app shows as static snapshot values; unverified ones read live data that could not be matched to the dashboard; drifted ones read live data checked on a later day than the dashboard ran, so their figures were expected to differ; tell the user which), or { status: "failed", error }. Poll every 15–30 seconds until it is done or failed.

getApp

ChatGPT
Alpha — the app content shape may change without a deprecation cycle. Reads the published content of an Omni app document behind an identifier: the complete HTML the app renders from, plus its sandbox settings. This is the app's whole artifact, often hundreds of kilobytes of HTML with no upper bound on read, so it is a real context cost: read one app at a time, once you know which one you need to understand or reason about. Whether a document is an app is not discoverable up front — a document that presents a dashboard, a report, or nothing answers 404, as does any app when the org has apps disabled, and that 404 is the cheap way to find out. The content is the published version; edits sitting in a draft are not included.

getAppDraft

ChatGPT
Alpha — the app content shape may change without a deprecation cycle. Reads the unpublished content of an Omni app document's main draft: the complete HTML and sandbox settings as they stand after any writes not yet published, including work other editors have saved to the same draft. This is what an app write edits, so read it before composing a change. A 404 carries a detail saying which state the document is in: 'This document has no main draft.' means no draft exists and getApp's published content is the current state; 'This draft has no app.' means the draft exists and its app was removed on it, a pending change that publishing makes live — report that state to the user and confirm before writing any content back. Like getApp, the read is the whole artifact with no upper bound, and a dashboard or a report answers 404 with its own detail.

getData

ChatGPT
Gets data by generating and executing a query from natural language. Use this when the user has a question that is asking for data. For example, "how many users do I have?", "what was sales like last month?". Keep the user's own wording where it carries meaning: qualifiers and filter conditions are read straight from the prompt, and relative dates like "last month" or "yesterday" are resolved server-side, so don't convert them to absolute dates. If a user provides SQL, study it, be succinct, and convert it to a plain english question describing what data the SQL is querying, then call this tool with that description as the prompt. The topicId is optional and rarely needed — omit it and the server picks the most appropriate topic for the prompt automatically (or surfaces a non-topic view when the server is configured for all-views-and-fields mode). Pass it only to scope the query to a topic you already have. Defaults to 1000 rows unless the prompt specifies a count; rowLimitHit: true in the response means the result is partial — say so, and re-ask with a row count if more are needed. The tool returns: 1. JSON Query results, (optional) 2. The filters applied to the query, (optional) 3. A workbook URL to view the full analysis within the Omni application -- If a workbook URL is present, always show it to the user. The response also includes 'topic' (real topic name, or null) and 'baseView' (base view name when queryAllViews surfaced a non-topic view, or null) — exactly one is non-null when a query was generated.

listBranches

ChatGPT
Lists the branches of a model, each with its 'id', 'name', and 'updatedAt'. Pass a branch's id as askOmni's branchId to work on that branch: queries run against it, model edits land there instead of in a new branch, and any dashboard or app built in the same turn is generated against it. Returns an empty list when the model has no branches.

listDocumentQueries

ChatGPT
Lists the saved queries in an existing Omni document — a dashboard, app, report, or plain workbook — behind an identifier. Returns one entry per query with its id, name, queryIdentifierMapKey, the field names it selects (fields) and already filters on (filterFields), and — unless the org hides links back to Omni — a URL. This is the document's full set, so it can include queries the document doesn't display. Use it to see what a document is built from, to get the queryIdentifierMapKey needed to run, schedule, or otherwise reference a single query, and to copy the exact field names a runSavedQuery filter needs.

listLlms

ChatGPT
Lists the AI LLMs Omni's agent can run askOmni on for this user (not data models), each with 'provider', 'model', 'label', 'description', 'thinkingLevels' and 'isDefault'. Call it only when the user asks for a specific or different LLM, including by description ("the fast one"): match what they said against each 'label' and 'description', then pass that entry's provider and model as askOmni's requestedLlm. Without a request, omit requestedLlm and the job runs on the 'isDefault' entry.

listSkills

ChatGPT
Reads an organization's saved skills — reusable instruction sets a person wrote for the Omni agent. Start with 'list' whether the user names a handle or describes a task, then read the one you want with 'skill'. Running a skill, saving one, editing one and deleting one are all askOmni's to do — name the skill in that tool's prompt. This tool only reads, so don't carry a skill's instructions out yourself with the other tools here. The caller sees every skill in the organization when they are an organization admin, and otherwise only the ones they created. 'skill' answers 404 when no live skill has that id and 403 when it belongs to another member the caller can't see.

patchApp

ChatGPT
Alpha — the app content shape may change without a deprecation cycle. Edits an Omni app document's HTML in place with targeted search-and-replace, without resending the whole page. Like putApp, the edit lands on the document's shared main draft (created on first write, reused after, possibly carrying other editors' unpublished work) and the published app is untouched until publishDraft is called for the same document. Edits run against the draft's current HTML: read it with getAppDraft first and copy each search verbatim from what it returned, following the branch its 404 describes. A search that no longer matches fails the request with 400 naming the edit rather than clobbering anything. Sandbox settings are not changed by this tool. Only edits an app that already exists — a document with no app is a 409 pointing at putApp; a dashboard or a report is a 422. If a call errors after the edit may have landed, read the draft again before retrying. Returns the document and draft identifiers, the document's name and description, the settings as stored, and any advisory warnings — prose whose wording can change, not something to branch on.

pickModel

ChatGPT
Returns a list of models available to the current API key. Each model has an id, a name, a modelKind, and — for a SHARED_EXTENSION — the baseModelId of the model it extends. An extension layers its own topics and fields on top of its base model and is queried exactly like any other model, so pick whichever one fits the question. Use this tool to discover which models are available before calling pickTopic or getData. For admin API keys, this returns all models in the organization. For user-scoped API keys, this returns only the models the user has access to. After calling this tool, select the most appropriate model for the user query and use its id when calling pickTopic and getData.

pickTopic

ChatGPT
Select the most appropriate topic based on the provided prompt. Returns a topicId that can be passed to getData to scope the query to a specific topic. Rarely needed: getData and askOmni pick a topic on their own, and calling this first splits one request into two, which risks the question being reformulated in between and losing filters or detail. Use it only when the topic choice needs to be shown to the user before querying.

publishDraft

ChatGPT
Publishes an Omni app document's main draft — the one the app write tools write to — so its content becomes what viewers of the document see. The whole draft is published, including any unpublished work other editors saved to it that this session did not write, and the draft is consumed: after this the document has no main draft until the next write creates one. Only documents whose main draft carries an app are published; a document with no app draft is refused without publishing anything. A document in a git-backed org that can only be edited through a branch is a 400 no retry fixes. Call it once the app content is in the state the user wants live; there is no undo beyond writing the previous content back. Returns the published document's identifier, name, and description.

putApp

ChatGPT
Alpha — the app content shape may change without a deprecation cycle. Replaces the HTML of an Omni app document on the document's main draft. The draft is created on first write and reused after — it is shared, so it may already carry unpublished work from other editors, and this write replaces the app HTML on it. Always read the draft with getAppDraft first and compose from what it returns, following the branch its 404 describes. Send the complete revised page: this is a whole-document replacement, last write wins, and the previous HTML is kept as a revision. The published app is untouched until publishDraft is called for the same document; the response carries the draft's identifier. Sandbox settings on an existing app are not changed by this tool; an app this call creates starts with the organization's locked-down defaults, and the response's app.settings is what was stored. A document that presents a dashboard or a report is refused (422) — a document presents as only one of the three; a workbook with no app yet becomes an app. If a call errors after the write may have landed, read the draft again before retrying. Returns the document and draft identifiers, the document's name and description, the settings as stored, and any advisory warnings — prose whose wording can change, not something to branch on.

queryUsageAnalytics

ChatGPT
Answer a question about how this organization uses this product (dashboard and workbook views, who viewed what and when, query activity, users, AI usage) by running one read-only usage analytics tool. This is product usage data, not the organization's own business data. Start with analytics_getData, passing the user's question in plain words with their qualifiers and relative dates kept. Use analytics_searchContent, analytics_listDocumentQueries and analytics_runSavedQuery to find and run the Analytics page's own saved reports; they search the analytics org, not this organization's dashboards, so a question about one of this organization's dashboards or users goes to analytics_getData by name. Results cover this organization only. The analytics workbooks behind them can't be opened by the user, so never offer a link to one. Not for exporting raw usage in bulk. Tools and their arguments: - analytics_getData: - prompt (required): The question to answer. Keep the user's qualifiers and filter conditions, and leave relative dates like "last month" as-is — the server resolves them. - topicId (optional): Optional and rarely needed. Omit it to let the server pick the best topic for the prompt. Pass a topic ID only to scope the query to a topic you already have. - analytics_pickTopic: - prompt (required) - analytics_searchContent: - limit (optional): Max results to return (default 10, max 25). - query (required): Keywords matched against names, descriptions, query names, folder names, labels, and creator names. Every term must match, so more words narrow the search: use 1-3 distinctive nouns ("revenue retention"), not a sentence ("show me the revenue dashboard" would also require "show" and "dashboard" to appear somewhere). There is no query syntax — OR, quotes, and * are stripped rather than interpreted. The last word matches as a prefix, so partial words are fine. If a search returns nothing, drop words rather than adding them. - analytics_listDocumentQueries: - identifier (required): The document identifier whose queries you want to list — the id in the document's URL, or the identifier analytics_searchContent returned. Works for any saved document: dashboard, app, report, or a workbook with none of those. Only unsaved analyses have nothing to list. - analytics_runSavedQuery: - filters (optional): Filters for this run, keyed by model field name as view.field. Copy the name from analytics_listDocumentQueries's fields or filterFields for the query; a guessed name fails the run. Each entry replaces the saved filter on that field for this run only, or is added when the query has none. Use it to scope a saved query to one customer, one id, or one date range instead of rebuilding the query. Value syntax. A bare value or array means equals: "CH-1042", ["west", "east"], 42, true, null (is null). Anything else is an object with one key naming the filter type, plus optional "case_insensitive": true on strings: - strings: { "is": "x" }, { "not": "x" }, { "contains": "x", "case_insensitive": true }, { "starts_with": "x" }, { "not": null } (not null) - numbers: { "greater_than": 100 }, { "less_than_or_equal_to": 5 }, { "between": [10, 100] } (end exclusive) - dates, prefer relative literals over computed dates: { "time_for_duration": ["30 days ago", "30 days"] } (the last 30 days), { "time_for_duration": ["2 complete years ago", "2 years"] }, { "between_dates": ["2025-01-01", "2025-02-01"] } (end exclusive, so the two ends must differ), { "between_dates": ["this month", "today"] } (month to date), { "on_or_after": "this january" }, { "before": "yesterday" }, { "is": "2 complete months ago" } (one period), { "is": "the previous Q3" }, { "is": "2025-03" } - recurring: { "day_of_week": "Monday" } means every Monday; for a specific day use { "is": "the previous monday" } - composite: { "or": [{ "is": "a" }, { "contains": "b" }] } - identifier (required): The document identifier the saved query lives on — a dashboard, app, report, or workbook. From analytics_searchContent or analytics_listDocumentQueries. - queryId (required): The saved query's…

readAppHtml

ChatGPT
Returns the stored HTML, query names, chart palettes, effective settings, frame CSP and SDK for a saved Omni app. Internal: called by the rendered app view, not by the driving LLM.

runAppQueries

ChatGPT
Runs a saved Omni app's queries by name and returns SDK-shaped results. Internal: called by the rendered app view, not by the driving LLM.

runQuery

ChatGPT
Runs an Omni query you supply as JSON and returns its rows. Reach for this whenever the query JSON is already in your context — the user pasted it, you ran it earlier in this conversation, or you have already composed it — and you want it run exactly as written, or with a small edit like a changed filter or limit. It executes the definition directly with no query generation step, so it spends no AI tokens and returns the same query you already have rather than a regenerated approximation of it. Use getData instead when you only have a question and need a query built for you — runQuery cannot discover field names. Requires the query API to be enabled for the org.

runSavedQuery

ChatGPT
Runs a pre-defined, vetted Omni query by id and returns its current results as JSON. Give the document identifier and the saved query's queryId (its queryIdentifierMapKey or id, from listDocumentQueries), optionally with filters overridden by field. Use this to execute a governed query that already exists in Omni without re-specifying it.

searchContent

ChatGPT
Free-text search over the org's existing dashboards and apps. Returns matches with each one's identifier, name, description, folder path, up to 5 query names from its workbook (the first few, not the ones that matched), whether it's verified, a 'type' of "dashboard" or "app", and — unless the org hides links back to Omni — a URL. Use this when the user references saved content ("the revenue dashboard", "my signups app") rather than asking a fresh data question. Pass a returned identifier to listDocumentQueries to see that workbook's queries.

searchDashboards

ChatGPT
Deprecated alias of searchContent — use searchContent.

searchOmniDocs

ChatGPT
Search the Omni documentation to answer questions about Omni features, configuration, modeling, dashboards, and more. Pass a natural language question and get a synthesized answer with source links.

showApp

ChatGPT
Asks the client to show an existing Omni app to the user as an inline interactive view. Only an MCP Apps host — one that renders interactive tool UI inline, such as Claude Desktop, claude.ai, ChatGPT, Cursor, VS Code with GitHub Copilot, or the Codex desktop app — renders that view. In any other client — a terminal such as Claude Code or the Codex CLI, or a chat client with no inline tool UI — nothing appears, so don't call this there: give the user the app's Omni link, read it with getApp, or run its queries with runSavedQuery instead. Give the document identifier of a saved app (from searchContent, listDocumentQueries, or a URL the user shared). To read or reason about the app's HTML itself, use getApp instead. The app renders itself and loads its own live data, so once it is showing there is no need to fetch or restate its numbers. If the user says no app appeared, fall back to getApp or runSavedQuery rather than assuming the numbers were shown.

startDashboardDownload

ChatGPT
Starts rendering an existing dashboard to a png image or a paged pdf, laid out as it is saved and as the acting user sees it, and returns a jobId right away without waiting. Use pdf for a large dashboard, or when a png came back too big to read. Tiles the user can't query, or whose query fails, render empty and the job still reports complete, so say the render may be missing tiles rather than asserting it is whole. Poll checkDashboardDownload with the jobId until its status leaves "in_progress": on "complete" call fetchDashboardDownload to get the file, on "error" report the reason it returns. One download per user per dashboard runs at a time: starting another while one is in progress is refused with the running job's id. Requires the dashboard to allow downloads.

submitFeedback

ChatGPT
Records the user's thumbs up or thumbs down on an answer from askOmni, the same signal as the thumbs under a response in the Omni chat UI. Call it only when the user states a verdict on the answer, never on your own judgement of it. Pass the jobId of the job that produced the answer and, when the user gave a reason, pass it as 'comment' in their words. Each call records a separate event, so call it once per answer. No tool reads feedback back; admins with AI Hub access see it on the AI Hub Quality dashboard in Omni.

Capabilities

WritesInteractive

Example Prompts

Click any prompt to copy it.

Similar Apps