> For the complete documentation index, see [llms.txt](https://k-ai.gitbook.io/knowledge-ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://k-ai.gitbook.io/knowledge-ai/k-ai-mcp/autonomous-agents.md).

# Autonomous agents (API key)

MCP's default authentication is [OAuth 2.1](/knowledge-ai/k-ai-mcp/oauth-flow.md), which puts a human at a consent screen. A fully autonomous agent platform has nobody to click it — so the OAuth dance either blocks the integration or, worse, leaves the agent hanging on a browser window that will never open.

For those callers, both K-AI MCP servers accept an [Organization API key](/knowledge-ai/authentication/organization-api-keys.md) **directly** in the `Authorization` header:

```
Authorization: Bearer ks_org_REDACTED
```

No OAuth, no browser, no token-exchange step. The key is a long-lived credential carrying organization roles; everything downstream — group RBAC, per-instance visibility, instructions, and the audit trail — behaves exactly as it does for a user token.

## Where the raw key is accepted

| Surface                                                   | Raw `ks_org_…` in `Authorization: Bearer`                                                                                              |
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Retrieval MCP — `https://api-retrieval.kai-studio.ai/mcp` | Yes                                                                                                                                    |
| Audit MCP — `https://api-audit.kai-studio.ai/mcp`         | Yes                                                                                                                                    |
| Retrieval API (REST) — `api-retrieval.kai-studio.ai`      | Yes                                                                                                                                    |
| Audit API (REST) — `api-audit.kai-studio.ai`              | Yes                                                                                                                                    |
| Platform API — `back.kai-studio.ai`                       | No — [exchange the key](/knowledge-ai/authentication/organization-api-keys.md#2-exchange-the-key-for-a-token) for a Bearer token first |
| Instance API — `api.kai-studio.ai`                        | No — uses [Instance API keys](/knowledge-ai/authentication/api-keys.md) (`instance-id` + `api-key`)                                    |

The key is read from the `Authorization` header only. It is never accepted in a cookie — a long-lived secret does not belong in one.

{% hint style="info" %}
Exchanging the key for a short-lived Bearer token still works everywhere and remains the right choice when your platform can hold a token cache. Sending the key directly trades that for one less moving part, which is usually what an agentic platform wants.
{% endhint %}

## 1. Create the key

Organization administrators create keys from the K-AI Studio portal → **Organization** → **API keys** → **Create key**. Grant the **minimum roles** the agent needs and copy the `ks_org_…` value — it is shown once.

Store it in a secret manager on the agent platform's server side. See [Organization API keys → Roles](/knowledge-ai/authentication/organization-api-keys.md#roles) for what each role grants.

## 2. Grant the key access

A key with valid credentials and no access reaches **nothing**. Both surfaces are fail-closed, and each grants access its own way.

### Retrieval

The key must belong to a **retrieval group** that contains at least one enabled, deployed knowledge base. This holds regardless of the roles the key carries — even `ADMIN` reaches no knowledge base through Retrieval without a group. An administrator adds it in the portal: **Organization** → **Activate** → **Groups** → pick a group → **API keys**. Keys appear in the member list with an `API key` badge.

Until then, `retrieval_instances_list_available_instances` returns an empty `instances` array plus a `notice` field explaining why:

```json
{
  "response": {
    "persona": null,
    "instances": [],
    "relationships": [],
    "notice": "No knowledge base is accessible to this identity. An organization administrator must add this user or API key to a retrieval group that contains at least one enabled, deployed knowledge base."
  }
}
```

That `notice` is the single most common symptom of a key plugged in before it was put in a group. The tool takes no arguments, so there is no other query to try and no knowledge base id to guess — relay the notice and stop.

### Audit

A key holding `ADMIN` or `STEWARD` sees and resolves every Clean item across the organization's audit instances. A key holding `KNOWLEDGE_EXPERT` needs to be added to an audit instance's team, and is then scoped to that instance. `AUTHORITY_MANAGER`, `ACTIVATION_MANAGER`, `BILLING`, and `CONSUMER` grant no Clean access on their own.

## 3. Connect

{% tabs %}
{% tab title="curl" %}

```bash
curl -s -X POST https://api-retrieval.kai-studio.ai/mcp \
  -H "Authorization: Bearer $KAI_ORG_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
        "protocolVersion":"2025-03-26",
        "capabilities":{},
        "clientInfo":{"name":"autonomous-agent","version":"1.0.0"}}}'
```

{% endtab %}

{% tab title="Python" %}

```python
import asyncio, os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def main():
    headers = {"Authorization": f"Bearer {os.environ['KAI_ORG_KEY']}"}
    async with streamablehttp_client(
        "https://api-retrieval.kai-studio.ai/mcp", headers=headers
    ) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool(
                "retrieval_instances_list_available_instances", {}
            )
            print(result.content)

asyncio.run(main())
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://api-retrieval.kai-studio.ai/mcp"),
  {
    requestInit: {
      headers: { Authorization: `Bearer ${process.env.KAI_ORG_KEY}` },
    },
  },
);

const client = new Client({ name: "autonomous-agent", version: "1.0.0" });
await client.connect(transport);

const result = await client.callTool({
  name: "retrieval_instances_list_available_instances",
  arguments: {},
});
console.log(result.content);
```

{% endtab %}
{% endtabs %}

Swap the host for `https://api-audit.kai-studio.ai/mcp` to drive the [Audit tools](/knowledge-ai/k-ai-mcp/audit-tools.md) with the same key.

## Error contract

The authentication path returns exactly two failure codes, and they mean opposite things. Wire your retry logic to this distinction — it is the contract, not an implementation detail.

| Code  | Meaning                                                                                                                             | What the agent should do                                                                   |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `401` | The key is invalid, revoked, or expired — or the deployment does not accept keys in Bearer.                                         | **Stop.** Surface the failure to an operator. Do not retry, and do not fall back to OAuth. |
| `503` | Authentication is momentarily unavailable or saturated. The credential is not implicated. A `Retry-After` header carries the delay. | **Retry** after `Retry-After` seconds.                                                     |

{% hint style="warning" %}
**Never treat `401` as a signal to start OAuth.** MCP hosts do exactly that: a `401` sends them to `/.well-known/oauth-authorization-server` and into an Authorization Code flow that requires a browser. An autonomous agent has no browser, so it hangs instead of failing. Treat `401` as fatal and report it.
{% endhint %}

Once authenticated, the usual per-tool codes apply — `403` for an instance the key's roles cannot reach, `400` for a malformed identifier, `422` for a schema violation. See [Errors & status codes](/knowledge-ai/reference/errors.md).

## Lifecycle

* **Revocation.** Revoking a key in the portal stops it authenticating new callers. Revocation is not instantaneous: allow a short propagation delay, and note that any Bearer token already minted from the key stops working when it expires. Plan for a short tail rather than an instant cut.
* **Expiry.** A key past its `expires_at` returns `401`. Set one where the integration's lifetime is known.
* **Rotation.** Create the replacement key, add it to the same groups and teams, deploy it, then revoke the old one. Both keys are live in between, so there is no gap.
* **One key per integration.** Separate keys let you revoke one agent platform without disrupting the others, and keep the audit trail readable — every call is attributed to the key that made it.

## Where to next

* [Organization API keys](/knowledge-ai/authentication/organization-api-keys.md) — the full auth model, roles, and the token-exchange alternative.
* [Retrieval tools](/knowledge-ai/k-ai-mcp/retrieval-tools.md) · [Audit tools](/knowledge-ai/k-ai-mcp/audit-tools.md) — the tool catalogs.
* [Cookbook](/knowledge-ai/k-ai-mcp/cookbook.md) — multi-tool recipes.
* [Connect a client](/knowledge-ai/k-ai-mcp/connect-a-client.md) — for interactive clients with a human present.
