Skip to main content
If you’re building your own AI chat into your application, your backend can mint an MCP token for each embed user. Your agent sends that token to Omni’s MCP Server, and Omni runs each query as that user. This is one of two ways to add AI chat to your embedded application. If you want to use the Omni Agent instead, see Embedding the Omni Agent.

How it works

MCP clients such as Claude or ChatGPT sign a user in through Omni’s OAuth flow. Embed users don’t sign in to Omni, so your backend vouches for them instead:
  1. Your backend calls createEmbedMcpToken from the @omni-co/embed SDK with the user’s identity and role values, the same as for a signed embed URL.
  2. The SDK signs a short-lived JWT with your embed secret and sends it to your Omni instance’s /oauth/token endpoint. This uses OAuth’s JWT-bearer grant (RFC 7523).
  3. Omni creates or updates the embed user, starts an embed session for them, and returns a standard OAuth access token.
  4. Your agent sends the token as Authorization: Bearer on every MCP request, the same as a token from the OAuth sign-in flow. Omni runs each query as that embed user.
The token lasts as long as the Session length setting in Settings > Embed, which defaults to 24 hours. There’s no refresh token. When Omni answers 401, your backend mints a new one.

Requirements

To follow the steps on this page, you’ll need:
  • Organization Admin permissions
  • The MCP server setting enabled in AI Hub > MCP
  • For Omni embed:
    • The Embed feature enabled in your Omni instance
    • Embed MCP tokens enabled for your organization. Reach out to Omni support to enable them.
    • An embed secret. If you already sign embed URLs, reuse that secret.
    • @omni-co/embed version 1.2.0 or later installed in your backend:

Setup

1

Mint a token for the user

On your server, mint a token with the user’s identity and roles. If you also embed Omni, you can use the same externalId and name as your embed URLs, so both belong to the same Omni user, but read the warning below first.
A token updates the embed user the same way an embed URL does, meaning Omni removes groups, attributes, roles, and entity settings that the token doesn’t include for every session. See How sessions update embed users for the full list.If your embed URLs and tokens use the same externalId, the most recent session wins. A token removes access that only your embed URL gives, and the next embed session removes access that only the token gives. To prevent this, do one of the following:
  • Send the same parameters in your embed URLs and your tokens for every session
  • Use a separate externalId for MCP, such as mcp:<your user ID>
If the user’s embed URL puts them in a group with a higher role, you must use a separate externalId. Omni refuses that group in a token, and if you leave it out, Omni removes it.
The token’s access comes only from its roles, so at least one of connectionRoles or modelRoles is required.
  • Use a standard role of Restricted Querier or Viewer, or a custom role that resolves to one of them, the same as for an embed URL. For a chat agent, use Restricted Querier or higher. A Viewer token can’t use getData or askOmni.
  • Omni refuses a groups or entity value that names a group with a higher role.
See the MCP token reference for every parameter the call accepts.Mint tokens on your server only, for the same reason you generate embed URLs server-side. The token itself is a credential for that user’s data until it expires, so proxy MCP calls through your backend instead of sending it to a browser.
The Omni TypeScript SDK uses Node’s crypto module, which is only available in Node environments. If your backend isn’t running Node, use the Direct request tab instead.
Call createEmbedMcpToken from the TypeScript SDK. If you use a custom domain, use the Custom domain tab to view an example call.
Mint a token with the SDK
Don’t hardcode user parameter values. Set user information like externalId, name, and userAttributes from your server’s own record of the signed in user. If these values are hard-coded, every user will have the same Omni identity and access.
A successful call returns accessToken and expiresAt.
2

Call the MCP Server as the user

Send the token from the previous step as a Bearer token to your Omni instance’s MCP endpoint. Omni serves the same endpoint at /mcp and /mcp/https, so use either path.If you also embed Omni, request the token on the same host your embed URLs use.
Omni identifies embed users by externalId and host, so a token from blobsrus.embed-omniapp.co and an embed URL on analytics.blobsrus.com are two different users.
Replace <MODEL_ID> with a model the user can query. Use the pickModel tool to list them.The token can call the tools that are enabled in AI Hub > MCP and that the user’s roles allow.
The MCP endpoints don’t support the X-MCP-User-ID or X-MCP-User-Required headers. Omni returns a 403 if a token request sends X-MCP-User-ID or sets X-MCP-User-Required: true.
3

Cache the token and implement 401 handling

Cache one token per externalId until shortly before its expiresAt, in a store all your servers share. Each call to createEmbedMcpToken ends the user’s previous token, so servers that each mint their own token will keep logging each other out.When Omni answers 401 - which means the token stopped working - call createEmbedMcpToken again and retry once:
Refresh on 401
Common causes of a 401 include:
  • A newer token was issued for the user
  • The token’s session was deleted or expired
  • The feature was turned off for your organization
Omni limits how many tokens each user can request in a short window. Over that limit, the call throws with the code rate_limited and a retryAfterSeconds value. Reuse the cached token instead of requesting another token.

Limiting what the agent can do

Omni gives each token only the tools that are enabled in AI Hub > MCP and that the user’s roles allow. For example, a Viewer token doesn’t get getData. To narrow what your agent can do for a user, combine the following:

Data access

  1. Use the connectionRoles, modelRoles, and userAttributes parameters in your mint calls to control which connections, models, and rows the user can query.
  2. Define access filters in your model to set up row-level filters using userAttributes. An attribute doesn’t filter anything until a topic’s access filter uses it. Take attribute values such as tenant_id from the user’s authenticated session on your server, never from a request the client controls.

Topics

  1. Use the ai_chat_topics model parameter to limit which topics the AI can pick.
  2. You can also use the X-MCP-Model-ID and X-MCP-Topic-Name headers to pin a session to one model or topic.

MCP tools

Your agent is the MCP client, so it decides which tools the LLM sees. After calling tools/list, pass only the tools you want, such as pickModel, pickTopic, and getData, to your LLM. Hosted agent APIs that take an MCP endpoint URL usually accept an allowed-tools list that does the same thing.
Omni doesn’t check which tools your agent passes to the LLM. On the server, Omni limits tools only by the AI Hub > MCP settings and the user’s roles. askOmni calls other tools on the server, and your tool list has no effect on those calls. What askOmni can do is limited only by the user’s own access.

Managing tokens

Tokens show up as embed sessions in Settings > Embed > Sessions. See Managing user sessions for more information. Rotating or deleting an embed secret doesn’t end tokens already issued. A token lives as long as its session, so to immediately end a token, delete the user’s session. Every active secret can sign new assertions, so you can add a new secret before you delete the old one. See Managing embed secrets for more information.

Troubleshooting

Another server minted a newer token for the same externalId, which ended this one. Share the token cache across your servers.
Check that the request doesn’t include X-MCP-User-ID or X-MCP-User-Required, and that the MCP server setting is enabled in AI Hub > MCP.
For every error createEmbedMcpToken can throw, see Error codes in the MCP token reference.

Next steps