# Agent Access (AI Support & Automation)

## What is it?

Programs (the AI support assistant, your own automations, third-party
systems) can access a limited, clearly defined set of functions in your
organization — the "tool layer" — without logging in as a human. The same
access also authenticates the [REST API](https://www.testlabiq.com/en/help/rest-api) (`/api/v1/projects`,
`/api/v1/test-cases`, …).

There are two ways in:

- **Sign in with OAuth** (for AI assistants like Claude, ChatGPT, Cursor or
  VS Code): you enter just the address, sign in in your browser and approve.
  You set this up yourself, no token needed — see "Connecting via MCP" below.
- **Agent token** (for automations without a person in front, e.g. scripts
  or servers): a fixed token in a header. We set these tokens up for you —
  there's no screen to issue them yourself yet; contact our team.

## How it works

- **Permissions:** Every programmatic access runs through the same permission
  model as a human member and only ever sees your own organization.
- **Traceable:** Every action is logged in the audit log with actor type
  *Agent* — with OAuth, also with the person the app acts on behalf of.

### Available tools (read-only)

- `search_docs` — searches this help documentation.
- `get_org_overview` — key figures (projects, stations, test objects, …).
- `get_calibration_status` — equipment calibrations due/overdue.
- `list_recent_audit_events` — recent changes (admin role only).
- `get_webhook_deliveries` — webhook delivery attempts (admin role only).
- `get_ingestion_deliveries` — measurement deliveries (REST/MQTT) with
  success/failure per station.
- `get_report_status` — current report status and stored failure reason,
  optionally filtered by report or project.
- `get_capacity_forecast` — capacity forecast per station type (utilisation,
  peak load, backlog, missing stations), optionally as a what-if; saves
  nothing (see [Capacity forecast](https://www.testlabiq.com/en/help/capacity-forecast)).

## Connecting via MCP (Model Context Protocol)

TestLabIQ ships a built-in MCP server. MCP is an open standard — the server
isn't tied to any particular AI vendor. Any client that speaks the
**Streamable HTTP** MCP transport works.

Address: `https://app.testlabiq.com/api/v1/agent/mcp`

### Recommended: sign in with OAuth

Enter just the address in your AI client. The first time it connects, the
client opens a browser window:

1. You sign in to TestLabIQ as usual.
2. You see which app wants access and where you'll be sent afterwards.
3. You choose the **organization** and **what the app may do**: *Read only*,
   *Read and edit* or *Manage* — at most your own role.
4. Click **Allow** and the app is connected.

From then on, the app acts **on your behalf**: the audit log shows each
action as *Agent — on behalf of* you. It can never do more than you: if your
role is lowered or you leave the organization, that applies to the app
immediately. Under **Settings → My settings → Connected apps** you see every
connection with its last use and can disconnect any of them instantly.

In common clients:

- **Claude (web, desktop, mobile)** and **ChatGPT**: add a custom connector
  (in ChatGPT, in developer mode) and enter the address above as the URL.
  Authentication: OAuth.
- **Claude Code**:

  ```
  claude mcp add -s user --transport http testlabiq https://app.testlabiq.com/api/v1/agent/mcp
  ```

  then run `/mcp` in a session and choose "Authenticate".
- **Cursor** (`~/.cursor/mcp.json`):

  ```json
  { "mcpServers": { "testlabiq": { "url": "https://app.testlabiq.com/api/v1/agent/mcp" } } }
  ```

- **VS Code / GitHub Copilot** (`.vscode/mcp.json` or "MCP: Open User
  Configuration"):

  ```json
  { "servers": { "testlabiq": { "type": "http", "url": "https://app.testlabiq.com/api/v1/agent/mcp" } } }
  ```

- **Other clients**: enter the address; if the client supports OAuth for MCP
  servers, sign-in starts on its own. It discovers our authorization server
  automatically (RFC 9728/8414 metadata) and registers itself (Dynamic Client
  Registration) — nothing else to configure.

The server name you enter in the client (`testlabiq` above) is up to you. For
several organizations, simply connect the app several times — you choose one
organization per connection.

### Alternative: agent token in a header

For automations without a person in front (scripts, servers, CI) there's the
fixed agent token. Send it in the `x-agent-token` header (or
`Authorization: Bearer <token>`); no browser sign-in involved.

**Claude Code:**

```
claude mcp add -s user --transport http testlabiq \
  https://app.testlabiq.com/api/v1/agent/mcp \
  -H 'x-agent-token: ${TESTLABIQ_TOKEN}'
```

Use single quotes so your shell doesn't expand the variable — the
placeholder is stored and resolved on every connection.

**Cursor:** as above, plus
`"headers": { "x-agent-token": "${env:TESTLABIQ_TOKEN}" }`.

**VS Code:** as above, plus
`"headers": { "x-agent-token": "${input:testlabiq-token}" }` and a matching
`"inputs"` entry (`"type": "promptString"`, `"password": true`) — VS Code then
prompts for the token once and stores it encrypted.

**Codex CLI** (`~/.codex/config.toml`):

```toml
[mcp_servers.testlabiq]
url = "https://app.testlabiq.com/api/v1/agent/mcp"
bearer_token_env_var = "TESTLABIQ_TOKEN"
```

**Your own agents** with the official MCP SDK (TypeScript):

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

const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(
  new StreamableHTTPClientTransport(new URL("https://app.testlabiq.com/api/v1/agent/mcp"), {
    requestInit: { headers: { "x-agent-token": process.env.TESTLABIQ_TOKEN! } },
  }),
);
const { tools } = await client.listTools();
```

In Python: `streamablehttp_client(url, headers={"x-agent-token": token})`.

### Testing the connection without a client (agent token)

```
curl -s https://app.testlabiq.com/api/v1/agent/mcp \
  -H "x-agent-token: $TESTLABIQ_TOKEN" \
  -H "content-type: application/json" \
  -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

If you get a list of tools back, your access works and any remaining issue
is in the client configuration. A `401` means the token is missing, wrong
or revoked.

### Which organization applies?

Not selectable per call, on purpose: no tool takes an organization as a
parameter, so even a manipulated instruction to the AI can't redirect it.

- **With OAuth** you choose the organization when approving; it applies to
  that one connection.
- **An agent token** is bound to exactly one organization when it's issued.
  To work with several organizations, get one token per organization and set
  up one MCP connection per token (e.g. `testlabiq-lab-north`,
  `testlabiq-lab-south`).

## Common issues

- **"I can't find a page to create or revoke a token."** AI assistants don't
  need one — connect via OAuth (see above) and disconnect under *Connected
  apps*. We set up fixed agent tokens for automations; contact our team for
  that or if something looks off.
- **"The client says 'needs authentication' / offers a sign-in."** With
  OAuth, that's the normal first step — start the sign-in. If you configured
  an agent token, it's missing or invalid (often the environment variable
  isn't set in the environment the client starts from; many clients don't
  read `.env` files).
- **"My organization is greyed out on the approval page."** Agent access is
  turned off for that organization (kill switch). Ask an administrator.
- **"I can only pick 'Read only'."** An app gets at most your own role.
- **"The app was connected and is suddenly signed out."** Possible reasons:
  you (or the app itself) disconnected it; you're no longer a member of the
  organization; or the app sent an already-used refresh token a second
  time — we treat that as possible theft and disconnect as a precaution. The
  reason is in the audit log ("AI app disconnected"). Just connect again.
- **"401 / Invalid token."** The configured token is wrong or has been
  revoked — or, with OAuth: the connection was disconnected or agent access
  for the organization was turned off.
- **"403 / Permission denied."** The configured access isn't allowed to use
  this tool. The diagnostic tools for audit and webhooks require admin
  rights.
- **"The agent sees data from another organization."** This can't happen:
  every access is bound to exactly one organization, and tenant isolation
  applies here too at the database level.

---

Source: https://www.testlabiq.com/en/help/agent-access
