> ## 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.

# Tool Calls

> Call MCP tools programmatically with the igris.mcp resource — initialize, listTools, and callTool over the gateway.

# Tool Calls

When you'd rather not wire up your own MCP client, the SDK exposes `igris.mcp` —
a small JSON-RPC client that speaks to the Igris gateway directly. Every call
is policy-evaluated, identity-tagged, and audit-logged exactly the same way
external MCP clients are.

## When to use this

| Use `igris.mcp.*` when…                                                     | Use `igris.connectHttp()` when…                                                                     |
| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| You're calling tools from server-side code (jobs, agents, schedulers)       | You're configuring an external MCP client (Claude Desktop, Cursor, VS Code, your own MCP-aware app) |
| You want zero extra dependencies on top of the SDK                          | You already use `@modelcontextprotocol/sdk` or another HTTP MCP client and want to keep that wiring |
| You want one return type (string content) instead of full JSON-RPC plumbing | You need raw access to MCP capabilities, prompts, resources, etc.                                   |

Both paths route through the same gateway, hit the same policies, and produce the same audit events.

## API

```typescript theme={null}
igris.mcp.initialize(slug, options?): Promise<{ protocolVersion, serverInfo }>
igris.mcp.listTools(slug, options?):  Promise<McpTool[]>
igris.mcp.callTool(slug, toolName, args, options?): Promise<string>
```

All three accept the same `McpConfigOptions`:

```typescript theme={null}
interface McpConfigOptions {
  user?: string;            // sent as X-Igris-User
  traceId?: string;         // sent as X-Igris-Trace-Id; auto-generated if omitted
  metadata?: Record<string, string | number | boolean>;
                            // sent as X-Igris-Metadata: <JSON>
}
```

## Quick Start

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

const igris = new Igris({ apiKey: process.env.IGRIS_API_KEY! });

// Optional handshake — useful for sanity checking that the connection is wired up.
const init = await igris.mcp.initialize("github-prod", {
  user: "alice@company.com",
});
console.log(init.serverInfo);
// { name: "github-mcp", version: "1.2.0" }

// Discover available tools.
const tools = await igris.mcp.listTools("github-prod", {
  user: "alice@company.com",
});
for (const tool of tools) {
  console.log(`${tool.name} — ${tool.description}`);
}

// Invoke a tool. The return value is the upstream tool's text content joined.
const output = await igris.mcp.callTool(
  "github-prod",
  "create_issue",
  {
    repo: "acme/igris",
    title: "Migration plan for v2",
    body: "Initial draft.",
  },
  {
    user: "alice@company.com",
    traceId: "trace-issue-triage-789",
    metadata: { feature: "issue-triage", env: "production" },
  },
);

console.log(output);
```

Every call hits `https://api.igrisecurity.com/v1/mcp/<slug>`, carries `Authorization: Bearer <apiKey>`, and is policy-evaluated server-side before being forwarded to the upstream MCP server with its real credential injected.

## Threading multiple calls under one trace

If a single user request triggers several tool calls, share the trace id so
Lens can show the whole chain as one operation:

```typescript theme={null}
const traceId = "trace-" + crypto.randomUUID();
const opts = { user: "alice@company.com", traceId };

await igris.mcp.callTool("github-prod", "list_issues", { repo: "acme/igris" }, opts);
await igris.mcp.callTool("slack-prod",  "post_message", {
  channel: "#triage",
  text: "Top 3 issues this week ...",
}, opts);
```

Both rows in the audit trail will share `traceId = "trace-..."`, which lets you
filter Lens to the full sequence.

## Error handling

`igris.mcp` methods (`igris.mcp.initialize`, `igris.mcp.listTools`, `igris.mcp.callTool`) throw
plain `Error` instances — **not** the typed `IgrisError` subclasses. The error message includes the
HTTP status and response body:

```
MCP gateway error (403): {"error":"policy denied"}
MCP error: tool not found
```

The typed error classes (`IgrisPolicyDeniedError`, `IgrisRateLimitError`, `IgrisAuthError`) apply
only to `igris.chat.completions`, `igris.embeddings`, and `igris.connections` — resources that use
`fetchWithRetry` internally. `igris.mcp` uses a plain `fetch` call.

Handle `igris.mcp` errors with a standard try/catch:

```typescript theme={null}
try {
  const output = await igris.mcp.callTool("github-prod", "delete_repo", { repo: "acme/legacy" });
} catch (e) {
  if (e instanceof Error) {
    if (e.message.includes("403")) {
      // policy denied or auth failure
    } else if (e.message.includes("429")) {
      // rate limited — implement your own backoff and retry
    } else {
      // upstream or gateway error
    }
  }
  throw e;
}
```

<Warning>
  `igris.mcp` does **not** auto-retry. Unlike the LLM gateway resources, `igris.mcp` makes a single
  `fetch` call with no retry logic. If you need resilience against transient errors or rate limits,
  implement your own retry loop with exponential backoff.
</Warning>

## What gets logged

Every `initialize`, `listTools`, and `callTool` produces an audit event with:

* The actor (`user`, derived from `X-Igris-User`)
* The connection slug
* The tool name and arguments (for `callTool`)
* The policy decision (`allow` / `deny` / `alert`)
* Any matched rule and conditions
* The trace id (`X-Igris-Trace-Id`)
* All metadata fields (`X-Igris-Metadata`)
* The timing and outcome

All of this surfaces in Lens and is queryable via the audit-events API.

## Related

* [Connections](/connect/connections) — how to register the upstream MCP server and store its credential
* [Identity & Metadata](/reference/sdk#identity--metadata) — what the gateway does with `user`, `traceId`, and `metadata`
* [Policies](/govern/policies) — how to gate `tools/call` by tool name, user, or metadata
* [MCP Client Config](/connect/mcp-config) — the alternative path: drive an external MCP client
