> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corsair.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent setup

> Canonical guide for coding agents setting up Corsair App — clarify intent, provision via the SDK, ask when ambiguous.

This is the single source of truth for setting up [Corsair App](https://app.corsair.dev) in a user’s project. Humans: read [Introduction](/app/home) first. Agents: follow this page end-to-end; fetch linked docs for path-specific details rather than guessing.

Package: `@corsair-dev/app` · Doc index: [llms.txt](https://docs.corsair.dev/llms.txt) · Integrations: [catalog](https://api.corsair.dev/md/integrations)

## Prerequisites

The user adds a developer API key to `.env` as `CORSAIR_DEV_KEY` ([create one](https://app.corsair.dev/api-keys)). Scope it to the relevant instance(s). Secrets are shown once — never log or commit them.

```bash theme={null}
npm install @corsair-dev/app
```

```ts theme={null}
import { createClient } from "@corsair-dev/app";

const corsair = createClient({ apiKey: process.env.CORSAIR_DEV_KEY! });
```

Use instance `id` (opaque), not display `name`, in API calls and env (`CORSAIR_INSTANCE_ID`).

## Goal

Use the SDK to provision and wire Corsair into the user’s project. Ask the user when something is ambiguous — do not guess instance names, tenant ids, or plugins from the repo folder name.

Prefer minimum project changes: env vars, a thin server helper if needed, and only the client config (MCP, etc.) the user asked for. Do not add committed setup scripts unless the user wants repeatable/CI provisioning.

The user connects OAuth / API keys via a connect link you mint in code (`t.connectLink.create()`), or in the dashboard for debugging.

## Flow overview

Work through these in order. Ask the user at any step when you cannot infer the answer from their message or discovery results.

1. Product intent — how will this project use Corsair?
2. Instance — find or create
3. Plugins — install what the project needs
4. Tenant — find or create
5. Wire the project — env, code, connect link, optional MCP/SDK config

***

## 1. Product intent

Before writing project code, understand what this product does with Corsair. If unclear, ask — e.g. *“What should this project do with Corsair — integrate a coding agent via MCP, add in-app chat, or call specific integrations from your backend/UI?”*

| Intent                                                           | What to set up                                                                                                                                  |
| ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| UI feeds, lists, dashboards (read-heavy)                         | [`tenant.run()`](/app/direct-execution) with **`*.db.*`** paths — read Corsair's synced cache; use **`*.api.*`** only on explicit refresh/write |
| Backend buttons, workflows, known API calls (writes or one-offs) | [`tenant.run()`](/app/direct-execution) with **`*.api.*`** paths — no agent loop                                                                |
| Cursor, Claude Code, Codex, etc.                                 | [Coding agent MCP](/app/coding-agents) + client config                                                                                          |
| In-app AI chat (Vercel AI, OpenAI, Claude SDK)                   | [Agent SDKs](/app/agent-sdks) — wire MCP tools; **do not** put Corsair operation names in the system prompt                                     |

Do not configure Cursor MCP (or any coding-agent client) just because you are running inside Cursor. Only set up MCP when the user wants that.

***

## 2. Instance

```ts theme={null}
const { instances } = await corsair.instances.list();
```

| Situation                            | Action                                                                                                             |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| No instances                         | Create one: `await corsair.instances.create({ name: "…" })` — use a sensible name from the project or ask the user |
| One instance                         | Use it unless the user said otherwise                                                                              |
| Multiple instances                   | Ask the user which to use — show `name` and `id` from the list                                                     |
| User named an instance               | Match by display `name`, then use its `id`                                                                         |
| `CORSAIR_INSTANCE_ID` already in env | Verify it exists; confirm with the user if discovery shows others                                                  |

```ts theme={null}
const inst = corsair.instance(instanceId);
```

See [Instances and plugins](/app/instances-and-plugins).

***

## 3. Plugins

```ts theme={null}
const { plugins } = await inst.plugins.list();
```

| Situation                                    | Action                                                                                                                              |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| User named integrations (e.g. GitHub, Slack) | `await inst.plugins.upsert("github", { mode: "cautious" })` — see [catalog](https://api.corsair.dev/md/integrations) for plugin ids |
| Unclear which plugins                        | Ask the user which services this project needs                                                                                      |
| Already installed                            | Skip unless the user wants config changes                                                                                           |

Use `useManaged: true` for managed OAuth when appropriate. Fetch [Instances and plugins](/app/instances-and-plugins) for auth types and permissions.

***

## 4. Tenant

```ts theme={null}
const { tenants } = await inst.tenants.list();
```

| Situation                          | Action                                                                                                                                                                       |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No tenants                         | Create one: `await inst.tenants.create("your-id")` or `await inst.tenants.create()` for a generated id — ask the user for a tenant id if this maps to their users/workspaces |
| One tenant                         | Ask the user to confirm, unless they already specified it                                                                                                                    |
| Multiple tenants                   | Ask the user which to use — show tenant ids from the list                                                                                                                    |
| `CORSAIR_TENANT_ID` already in env | Verify it exists on the instance                                                                                                                                             |

Never invent tenant ids from the repo or folder name. List tenants and ask, or use an id the user provides.

```ts theme={null}
const t = inst.tenant(tenantId);
```

See [Tenants and auth](/app/tenants-and-auth).

***

## 5. Wire the project

1. `npm install @corsair-dev/app` if not already present
2. Persist env (never commit secrets): `CORSAIR_DEV_KEY`, `CORSAIR_INSTANCE_ID`, `CORSAIR_TENANT_ID`
3. Add a thin server helper if the app will call Corsair — e.g. `src/lib/corsair.ts`:

```ts theme={null}
import { createClient } from "@corsair-dev/app";

export const corsair = createClient({ apiKey: process.env.CORSAIR_DEV_KEY! });

export function corsairTenant(tenantId = process.env.CORSAIR_TENANT_ID!) {
  return corsair.instance(process.env.CORSAIR_INSTANCE_ID!).tenant(tenantId);
}
```

4. Connect accounts — if the tenant still needs OAuth or API keys:

```ts theme={null}
const { url } = await t.connectLink.create(); // optional: { plugins: ["github"] }
// Send url to the user to open in a browser
```

### Pick operations from the catalog

Fetch the [integrations catalog](https://api.corsair.dev/md/integrations) — same data as MCP `list_operations` / `get_schema`, as markdown:

1. `https://api.corsair.dev/md/integrations` — plugin ids
2. `https://api.corsair.dev/md/integrations/github` — all paths for a plugin (`*.api.*`, `*.db.*`, webhooks)
3. `https://api.corsair.dev/md/integrations/github.api.issues.list` — input/output schema for one path

Use those paths in `tenant.run()`. No separate probe step — read the catalog, then call the endpoint.

### Direct execution (backend / UI)

See [Direct execution](/app/direct-execution).

**Read-heavy UI (feeds, search, detail pages):** prefer **`github.db.*`** (or `<plugin>.db.*`) so the app reads Corsair's synced database instead of calling the third-party API on every page load. Add a user-triggered **Resync** (or similar) that calls **`*.api.*`** list endpoints to refresh the cache, then re-read from **`*.db.*`**.

**Writes and one-off actions:** use **`*.api.*`** via `tenant.run()` when the backend already knows the exact operation.

```ts theme={null}
// Read open issues from the synced cache (good for a feed)
const { data: rows } = await t.run("github.db.issues.search", {
  data: { url: { contains: "corsairdev/corsair" } },
  limit: 100,
  offset: 0,
});

// Refresh cache from GitHub (good for a Resync button)
await t.run("github.api.issues.list", {
  owner: "corsairdev",
  repo: "corsair",
  state: "open",
  perPage: 100,
});

// Write when the user clicks a button
const result = await t.run("github.api.issues.createComment", {
  owner: "corsairdev",
  repo: "corsair",
  issueNumber: 42,
  body: "Thanks for the report!",
});

if (!result.success) {
  // redirect user to result.signInLink
}
```

### Coding agent MCP (only when requested)

See [Coding agents](/app/coding-agents) and the client page (e.g. [Cursor](/app/coding-agents/cursor)).

```ts theme={null}
const conn = await t.mcpKeys.connection();
const key = await t.mcpKeys.create("cursor"); // secret shown once → CORSAIR_MCP_SECRET
// Wire only the client the user asked for (e.g. .cursor/mcp.json)
```

### Agent SDK (only when requested)

See [Agent SDKs](/app/agent-sdks). Prefer `tenant.mcp.createVercelClient()` when the server holds `CORSAIR_DEV_KEY`.

Wire the MCP client and pass `await mcpClient.tools()` to your harness. **Do not** add Corsair operation names, `run_script` usage, or plugin paths to the system prompt — the hosted MCP server exposes **`list_operations`**, **`get_schema`**, and **`run_script`** so the agent discovers and invokes operations itself. Keep the system prompt to product context only (e.g. which repo or tenant the app serves).

***

## Reference

| Topic                                  | Doc                                                                        |
| -------------------------------------- | -------------------------------------------------------------------------- |
| Integrations catalog (paths + schemas) | [api.corsair.dev/md/integrations](https://api.corsair.dev/md/integrations) |
| Instances, plugins, permissions        | [Instances and plugins](/app/instances-and-plugins)                        |
| Tenants, connect links, OAuth          | [Tenants and auth](/app/tenants-and-auth)                                  |
| Types and errors                       | [Types and errors](/app/types-and-errors)                                  |
| Installation (API overview)            | [Installation](/app/installation)                                          |

## Safety rules

* Never log or expose tenant API key secrets, OAuth tokens, or plugin credentials
* Permission requests must be approved in Corsair; agents cannot bypass them
* Ask the user when instance, tenant, or plugin choice is ambiguous — do not hardcode or guess from repo metadata
* Avoid extra setup scripts, env keys, and MCP config the user did not ask for

## Self-hosted SDK

Use only when the user explicitly wants Corsair in their own process: [SDK introduction](/getting-started/introduction), [quick start](/getting-started/quick-start), [MCP adapters](/mcp-adapters/mcp-adapters) (stdio MCP, not hosted App).
