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

# SDK Reference

> Complete reference for @igris-security/sdk — MCP governance and LLM gateway client.

# Igris SDK

The Igris SDK (`@igris-security/sdk`) is a TypeScript client for the Igris governance gateway. It generates MCP client configurations, calls MCP tools programmatically, and provides a native OpenAI-compatible interface for the LLM gateway.

## Installation

```bash theme={null}
npm install @igris-security/sdk
```

## Initialize

```typescript theme={null}
import { Igris } from "@igris-security/sdk";

const igris = new Igris({
  apiKey: "ig_...",  // Your Igris API key
});
```

The `baseUrl` option can also be set via the `IGRIS_BASE_URL` environment variable.

<Warning>
  Never commit your API key to source control. Use environment variables:

  ```typescript theme={null}
  const igris = new Igris({ apiKey: process.env.IGRIS_API_KEY! });
  ```
</Warning>

## Get Your API Key

1. Log in to the [Igris Dashboard](https://app.igrisecurity.com)
2. Go to **Settings → API Keys**
3. Click **Generate API Key**
4. Copy the key — it's shown only once

***

## MCP Connections

### `igris.connectHttp(slug, options?)`

Generate an HTTP connection config for any external MCP client.

```typescript theme={null}
const config = igris.connectHttp("github-prod", {
  user: "alice@company.com",
  traceId: "req_abc123",
  metadata: { role: "developer", team: "engineering" },
});

// config.baseUrl  → "https://api.igrisecurity.com/v1/mcp/github-prod"
// config.apiKey   → "ig_..."
// config.headers  → { "X-Igris-Trace-Id": "ig_trace_...", "X-Igris-User": "alice@company.com", ... }
```

Pass the result to any MCP client:

```typescript theme={null}
const response = await fetch(config.baseUrl, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${config.apiKey}`,
    "Content-Type": "application/json",
    ...config.headers,
  },
  body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list", params: {} }),
});
```

**Return type:**

```typescript theme={null}
interface HttpConnection {
  baseUrl: string;
  apiKey: string;
  headers: Record<string, string>;
}
```

***

## Identity & Metadata

Pass user identity and freeform metadata with every MCP or LLM request. Igris uses this for policy evaluation, audit trails, and trace correlation.

### How It Works

The SDK translates identity options into HTTP headers:

| SDK Parameter | HTTP Header        | Purpose                                  |
| ------------- | ------------------ | ---------------------------------------- |
| `user`        | `X-Igris-User`     | End-user identity (opaque string)        |
| `traceId`     | `X-Igris-Trace-Id` | Cross-call correlation                   |
| `metadata`    | `X-Igris-Metadata` | JSON key-value pairs for policy matching |

All fields are **optional**. If omitted, the gateway still works — just without identity-based policies or user-level audit.

### Trace IDs

Trace IDs group multiple tool calls from a single user request:

```typescript theme={null}
const traceId = "req_abc123";

const githubConfig = igris.connectHttp("github-prod", { traceId, user: "alice" });
const slackConfig  = igris.connectHttp("slack-prod",  { traceId, user: "alice" });
```

**Auto-generation:** If you don't pass a `traceId`, the SDK generates one automatically (`ig_trace_` + random hex). Each `connectHttp()` call gets its own trace ID.

### Metadata for Policies

Metadata enables attribute-based access control:

```typescript theme={null}
metadata: {
  role: "developer",
  team: "engineering",
  environment: "production",
  customerId: "cust_456",
}
```

Then write policies that match on these fields:

```json theme={null}
{
  "rules": [
    { "tool": "delete_*", "action": "deny", "conditions": { "metadata.role": "intern" } },
    { "tool": "*",        "action": "allow" }
  ]
}
```

**Condition operators:**

| Operator           | Example                                       | Meaning            |
| ------------------ | --------------------------------------------- | ------------------ |
| String (shorthand) | `"metadata.role": "intern"`                   | Equals "intern"    |
| `eq`               | `"metadata.role": { "eq": "intern" }`         | Equals "intern"    |
| `neq`              | `"metadata.role": { "neq": "admin" }`         | Not equals "admin" |
| `in`               | `"metadata.role": { "in": ["dev", "admin"] }` | Value in list      |
| `nin`              | `"metadata.role": { "nin": ["intern"] }`      | Value not in list  |

If a policy condition references a field that is absent from the request, the rule is skipped — not denied.

**Metadata limits:**

| Constraint   | Limit                              |
| ------------ | ---------------------------------- |
| Max size     | 4 KB                               |
| Max nesting  | 3 levels                           |
| Key format   | No dots in key names               |
| Invalid JSON | Header ignored (treated as absent) |

<Warning>
  **User-based policies are advisory, not security boundaries.** Any holder of an API key can set any `X-Igris-User` value. The API key is the real trust anchor.
</Warning>

***

## LLM Gateway

### `igris.chat.completions.create(request)`

Send a chat completion through the Igris LLM gateway. The `model` field must use `@slug/model` syntax.

**Non-streaming:**

```typescript theme={null}
const response = await igris.chat.completions.create({
  model: "@openai-prod/gpt-4o",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user",   content: "What is the capital of France?" },
  ],
  max_tokens: 200,
  temperature: 0.7,
});

console.log(response.choices[0].message.content);
console.log(response.usage.total_tokens);
```

**Streaming:**

```typescript theme={null}
const stream = await igris.chat.completions.create({
  model: "@openai-prod/gpt-4o",
  messages: [{ role: "user", content: "Write a short story" }],
  stream: true,
});

for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) process.stdout.write(delta);
}
```

### `igris.embeddings.create(request)`

```typescript theme={null}
const response = await igris.embeddings.create({
  model: "@openai-prod/text-embedding-3-small",
  input: ["Hello world", "Goodbye world"],
});

console.log(response.data[0].embedding.length); // e.g. 1536
```

### `igris.llmProviders.list()`

Fetch all registered LLM provider slugs and metadata:

```typescript theme={null}
const providers = await igris.llmProviders.list();
for (const p of providers) {
  console.log(`${p.slug} → ${p.name} (${p.authStyle})`);
}
```

### `igris.connectLlm(slug, options?)`

Build an `LlmConnection` for use with any OpenAI-compatible SDK client:

```typescript theme={null}
const conn = igris.connectLlm("openai-prod", {
  user: "alice@corp.com",
  traceId: "trace-abc123",
  metadata: { role: "developer", team: "platform" },
});

// conn.baseUrl → "https://api.igrisecurity.com/llm/openai-prod/v1"
// conn.apiKey  → your Igris API key
// conn.headers → X-Igris-User, X-Igris-Trace-Id, X-Igris-Metadata-* headers
```

***

## LLM Types

### `ChatMessage`

```typescript theme={null}
interface ChatMessage {
  role: "system" | "user" | "assistant" | "tool";
  content: string | Array<{ type: string; text?: string; [key: string]: unknown }>;
  name?: string;
  tool_call_id?: string;
  tool_calls?: unknown[];
  reasoning_content?: string;  // extended thinking output (e.g. Claude reasoning)
}
```

### `ChatCompletionUsage`

```typescript theme={null}
interface ChatCompletionUsage {
  prompt_tokens: number;
  completion_tokens: number;
  total_tokens: number;
  prompt_tokens_details?: { cached_tokens?: number };
  completion_tokens_details?: { reasoning_tokens?: number };
}
```

### `ChatCompletionResponse`

```typescript theme={null}
interface ChatCompletionResponse {
  id: string;
  object: "chat.completion";
  created: number;
  model: string;
  choices: ChatCompletionChoice[];
  usage: ChatCompletionUsage;
}
```

### `ChatCompletionChunk` (streaming)

```typescript theme={null}
interface ChatCompletionChunk {
  id: string;
  object: "chat.completion.chunk";
  created: number;
  model: string;
  choices: Array<{
    index: number;
    delta: Partial<ChatMessage>;
    finish_reason: string | null;
  }>;
  usage?: ChatCompletionUsage;  // present on the final chunk
}
```

***

## Subpath Adapters

Zero-migration integration with existing SDK clients. All adapters are exported from `@igris-security/sdk/adapters/{openai,anthropic,google}`.

### OpenAI adapter

```typescript theme={null}
import OpenAI from "openai";
import { Igris } from "@igris-security/sdk";
import { withIgris } from "@igris-security/sdk/adapters/openai";

const igris = new Igris({ apiKey: "ig_..." });

const openai = withIgris(
  new OpenAI({ apiKey: "placeholder" }),
  igris,
  "openai-prod",
  { user: "alice@corp.com" },
);

// Works exactly like the native OpenAI client
await openai.chat.completions.create({ model: "gpt-4o", messages: [...] });
```

### Anthropic adapter

```typescript theme={null}
import Anthropic from "@anthropic-ai/sdk";
import { withIgris } from "@igris-security/sdk/adapters/anthropic";

const anthropic = withIgris(new Anthropic({ apiKey: "placeholder" }), igris, "anthropic-prod");

await anthropic.messages.create({
  model: "claude-3-5-sonnet-20241022",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Hello!" }],
});
```

### Google adapter (stub)

Google's SDK does not expose a unified `baseURL` override. The Google adapter returns the `LlmConnection` config for manual use.

```typescript theme={null}
import { withIgris } from "@igris-security/sdk/adapters/google";

const conn = withIgris(null, igris, "google-prod");
// conn.baseUrl / conn.apiKey / conn.headers — apply manually
```

***

## Typed Errors

All SDK methods throw typed errors on non-2xx responses:

```typescript theme={null}
import {
  IgrisError,
  IgrisAuthError,
  IgrisPolicyDeniedError,
  IgrisRateLimitError,
  IgrisConflictError,
  IgrisValidationError,
} from "@igris-security/sdk";

try {
  await igris.chat.completions.create({ model: "@openai-prod/gpt-4o", messages: [...] });
} catch (err) {
  if (err instanceof IgrisPolicyDeniedError) {
    console.error("Blocked by policy:", err.message);      // HTTP 403
  } else if (err instanceof IgrisRateLimitError) {
    console.error("Rate limited:", err.message);            // HTTP 429
  } else if (err instanceof IgrisAuthError) {
    console.error("Auth error:", err.message);              // HTTP 401
  } else if (err instanceof IgrisError) {
    console.error("Gateway error:", err.message, err.response);
  }
}
```

**Error class hierarchy:**

| Class                    | HTTP Status |
| ------------------------ | ----------- |
| `IgrisAuthError`         | 401         |
| `IgrisPolicyDeniedError` | 403         |
| `IgrisConflictError`     | 409         |
| `IgrisValidationError`   | 422         |
| `IgrisRateLimitError`    | 429         |
| `IgrisError`             | any other   |

***

## Environment Variables

| Variable         | Default                        | Description               |
| ---------------- | ------------------------------ | ------------------------- |
| `IGRIS_BASE_URL` | `https://api.igrisecurity.com` | Override gateway base URL |

<CardGroup cols={2}>
  <Card title="Tool Calls" icon="play" href="/govern/tool-calls">
    Call MCP tools programmatically with `igris.mcp`.
  </Card>

  <Card title="Connections" icon="key" href="/connect/connections">
    Create and manage encrypted credential vaults.
  </Card>

  <Card title="MCP Client Config" icon="plug" href="/connect/mcp-config">
    Generate configs for Claude Desktop, Cursor, and more.
  </Card>

  <Card title="API Reference" icon="brackets-curly" href="/reference/api">
    REST API endpoints for all Igris resources.
  </Card>
</CardGroup>
