Skip to main content

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.

Once an instance has plugins and a tenant has credentials, you have two ways to use Corsair:
  • Give an AI agent the tenant’s MCP endpoint and API key
  • Call a single plugin operation directly from your backend with tenant.run()

Create an MCP key

MCP keys are scoped to one tenant. They let MCP-compatible clients call the tenant’s installed and permitted plugin operations.
const inst = corsair.instance(process.env.CORSAIR_INSTANCE_ID!);
const tenant = inst.tenant("user_123");

const key = await tenant.mcpKeys.create("production-agent");

console.log(key.mcpHttpUrl);
console.log(key.secret);
key.secret is returned exactly once. Store it securely if your app needs to use it later.

Connection info

Fetch connection metadata without creating a new secret:
const connection = await tenant.mcpKeys.connection();

console.log(connection.mcpHttpUrl);
console.log(connection.oauthDiscoveryUrl);
console.log(connection.protectedResourceMetadataUrl);
Use this when your UI needs to show the MCP endpoint after setup.

List and revoke keys

const { keys } = await tenant.mcpKeys.list();

for (const key of keys) {
  console.log(key.name, key.keyPrefix, key.lastUsedAt);
}
await tenant.mcpKeys.revoke("key_123");
Revoked keys receive authentication errors immediately.

Connect an MCP client

Use the created mcpHttpUrl as the MCP server URL and the secret as the bearer token.
const key = await tenant.mcpKeys.create("chat-agent");

const mcp = {
  url: key.mcpHttpUrl,
  headers: {
    Authorization: `Bearer ${key.secret}`,
  },
};
Different AI frameworks shape MCP configuration differently. The important parts are the same: the URL comes from mcpHttpUrl, and authorization uses the tenant MCP secret.
For framework-specific MCP examples, see the MCP adapter guides in the Docs tab. The Hosted SDK gives you the hosted URL and tenant secret those adapters need.

Run one operation directly

Use tenant.run() when your backend wants to call a plugin operation without going through an agent loop.
const result = await tenant.run("slack.api.messages.post", {
  channel: "#general",
  text: "Hello from Corsair Hosted",
});

console.log(result.data);
The operation path uses the catalog’s dot-separated path format.
await tenant.run("github.api.repositories.star", {
  owner: "corsairdev",
  repo: "corsair",
});
For read operations with no input, omit the second argument:
const { data } = await tenant.run<{ messages: unknown[] }>(
  "gmail.api.messages.list",
);

Permissions still apply

Direct execution uses the same server-side permission enforcement as MCP. If the instance policy denies an operation or requires approval, tenant.run() will not bypass it.
await inst.plugins.permissions.setOverride(
  "github",
  "api.repositories.delete",
  "deny",
);

await tenant.run("github.api.repositories.delete", {
  owner: "acme",
  repo: "legacy",
});
// Throws CorsairApiError with a 403 response.

Choosing MCP or run

Use caseRecommended path
Agent can discover tools and decide what to callMCP
Your backend already knows the exact operationtenant.run()
Multi-turn assistant with many possible appsMCP
Scheduled job or deterministic workflow steptenant.run()
End-user brings their own MCP clientTenant MCP key

Example: agent setup endpoint

import { createClient } from "@corsair-dev/app";

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

export async function createAgentConnection(userId: string) {
  const inst = corsair.instance(process.env.CORSAIR_INSTANCE_ID!);
  const tenant = inst.tenant(userId);

  const key = await tenant.mcpKeys.create("agent");

  return {
    mcpHttpUrl: key.mcpHttpUrl,
    bearerToken: key.secret,
  };
}

Example: deterministic workflow

export async function notifyWorkspace(workspaceId: string, text: string) {
  const inst = corsair.instance(process.env.CORSAIR_INSTANCE_ID!);
  const tenant = inst.tenant(workspaceId);

  await tenant.run("slack.api.messages.post", {
    channel: "#alerts",
    text,
  });
}