Agentic apps on your data, with your own LLM keys
Three ways an agent can reach Supero data — the built-in one, your code calling a model you pay for, and your own agent driving the platform over MCP.
Once you want your own model, your own prompts and your own agent loop, the question becomes which boundary the model sits behind. There are three answers, they have different governance properties, and mixing them up is the usual mistake.
Three boundaries, not one feature
Teams arrive at this article with one of three real requirements, and they sound similar enough to get conflated: "we need our own model", "we need our own prompts", and "we need our own agent loop". They land in different places.
| What you actually need | Where the model sits | Whose keys |
|---|---|---|
| End users asking about their own data, no setup | Built-in in-app agent | Supero's — included in your plan |
| A "summarise this" button, a draft-reply field, a classification step | services.ai from your app code | Yours — OpenAI and/or Anthropic |
| Your own agent loop, your own tools, your own orchestration | Your agent, driving Supero over MCP | Yours, wherever your agent runs |
| A model you host, or a provider not in the catalog | Your endpoint, via the plugin registry | Yours, stored on the platform side |
services.ai — your model, your prompt, your bill
When your app itself needs a model — not a chat surface, but a feature — ai is a catalog service like any other. You import it and configure it with your own provider keys, which is the point: the calls bill to your account, and you choose the provider.
curl -X POST https://api.supero.dev/api/v1/services/import \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"service_id": "ai",
"domain": "acme-corp",
"project_uuid": "8f2a1c40-...",
"config_data": {
"openai_api_key": "sk-...",
"anthropic_api_key": "sk-ant-..."
}
}'From your app code, call it through the wrappers rather than hand-building a request. Two operations cover almost everything: a single completion and a chat exchange.
// a "summarise this ticket" button in ui/app.js
const res = await services.ai.complete({
prompt: 'Summarize this support ticket in one sentence:\n\n' + ticket.body,
model: 'gpt-4o', // pass one, or you silently get the default
});
const summary = res.output.generated_text;
// a multi-turn exchange your own code drives
const chat = await services.ai.chat({
messages: [
{ role: 'system', content: 'You draft replies in our support voice.' },
{ role: 'user', content: ticket.body },
],
model: 'gpt-4o',
});
const reply = chat.output.generated_text;- The key is stored encrypted at rest on Supero Cloud and returned masked — your application code never holds it.
- Scope matters: service credentials belong to the project. Every tenant in a project shares one set of provider keys. A customer who must bring their own key needs their own project, or their own endpoint via the plugin registry.
services.aihas to be imported before it works — and an un-imported call does not throw. It resolves with HTTP 200 and{success: false, error: "Service 'ai' is not imported in this project"}, so atry/catchcatches nothing andres.output.generated_textisundefined. Branch onres.successbefore you read the text. Imported-but-unconfigured is a different shape again:error_code: "ConfigValidationError"withstatus_code: 503.- Always pass a `model`. Omit it and the browser wrapper substitutes a hard-coded
'claude-sonnet'— which is not a valid Anthropic model id and forces the Anthropic path, so an OpenAI-only project gets a 503 and an Anthropic one gets a 4xx. Either way it looks like a broken integration rather than a missing argument. Use a real id:claude-sonnet-5,gpt-4o. - Both return an execute envelope, not a bare string: read
result.output.generated_text. Over the wire the operation ids aresimple_completionandchat_completion;completeandchatare the browser wrappers.
Your agent, driving Supero over MCP
This is the one people mean by "agentic". Your agent runs wherever you run it — your infrastructure, your model, your keys, your orchestration framework — and reaches Supero over the Model Context Protocol. Supero becomes a governed tool surface rather than the thing running the loop.
The connection is one endpoint — POST /mcp/v1/messages, JSON-RPC 2.0 over Streamable HTTP — and scope comes entirely from the credential, so there is no domain segment in the URL.
| Credential your agent uses | Resolves to | Can do |
|---|---|---|
| Project-admin key | project_admin | Build and operate within that one project |
| Domain-admin key | domain_admin | Any project in the domain, and create new ones |
| Tenant-scoped key | tenant_user | Refused for build tools |
| Plain JWT session | jwt | Read-only; refused for publish, deploy, teardown |
A model you host, or a provider not in the catalog
If the model runs on your own infrastructure — a fine-tuned model, a self-hosted open-weights deployment, a provider the catalog does not carry — register it as a plugin. A plugin is one HTTP endpoint plus the retry and breaker behaviour you would otherwise write.
curl -X POST https://api.supero.dev/api/v1/plugins/register \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"project_uuid": "8f14e45f-...",
"plugin_name": "internal-llm-gateway",
"endpoint_url": "https://llm.internal.example.com/v1/complete",
"http_method": "POST",
"auth_type": "header",
"auth_header_name": "X-Api-Key",
"auth_header_value": "REDACTED",
"timeout_seconds": 120
}'- The credential is attached on the platform side from the stored value and redacted on read — it never travels through your application code.
- Your endpoint receives the payload wrapped:
{"object": { …your fields… }, "metadata": { project_uuid, request_id, timestamp }}. Read your fields offobject. - Raise
timeout_seconds— the 30-second default is short for a large generation. 300 is the documented ceiling, and nothing enforces it for you. - Plugins are domain-scoped: one name per domain, resolvable from any project in it.
- A data-triggered call to
services.aineeds no glue — aservice_callstep naming serviceaiand operationsimple_completionworks directly, because it is a catalog service. It is a plugin you registered that no step type can reach: there is no plugin step type, so that path goes through a workflow step calling code of yours.
Self-hosted: the built-in agent, on your own model
There is one configuration where the two halves of this article collapse into one: the on-premise native AI agent add-on. Self-hosted, the agent is configured with your own LLM provider credentials and never calls a Supero-hosted model at all — which is the answer for a buyer whose requirement is not "our keys" but "our network".
- It is a separately licensed add-on, not part of the base on-premise package — as are the connectors and the integrations catalog. It stays off until it is both installed and named in the signed licence.
- You still build and generate apps in Supero Cloud; on-premise is where you deploy and run them.
- This is the only place the in-app agent takes a key of yours. On Supero Cloud it does not.
Which boundary for which requirement
| Requirement | Answer |
|---|---|
| "Our users want to ask questions about their data" | Built-in agent. Do not build this. |
| "We need a summarise button" | services.ai with your keys |
| "Our security team wants the model calls on our account" | services.ai, or your own agent over MCP |
| "Each customer brings their own OpenAI key" | A project per customer, or their endpoint via the plugin registry |
| "We have an agent framework already and want Supero as a tool" | MCP, with a project-scoped key |
| "The model must never leave our network" | Self-hosted platform with the native AI agent add-on, or your own endpoint via the plugin registry. Deploying the app to your own cloud does not move the platform. |
What this does not give you
- Provider keys are per project, not per tenant. "Every customer brings their own model key" is a project-per-customer decision or a plugin, not a config field.
- `services.ai` is a call, not a loop. No tools, no memory, no gates. Building an agent on top of it means building all of that yourself.
- Your own agent over MCP means your own everything: retries, cost control, prompt-injection defence, evaluation, and audit of what the loop did. Supero governs what the key can reach — not what your loop decides to try.
- Deploying the app to your own AWS or GCP does not move the platform. Data, auth and AI generation stay on the Supero backend unless you self-host, where the AI agent is a separately licensed add-on.
- On Supero Cloud the built-in agent runs on Supero's models, drawn from your plan allowance — there is no path from a project's
aiconfig into it, so it is not a place to plug your own key in. Self-hosting is the exception; see below.
Where to go from here
- Start with the one that needs no setup: Give your app an AI agent over its own data.
- The full MCP tool surface and the quality gates: A field-service platform built from your AI editor.
- Plugin registry in depth: Extending Supero: your own endpoints.
Build this on Supero
Describe it and get schemas, APIs, SDKs and a governed multi-tenant backend — or point your own AI editor at Supero over MCP and build it there.