---
title: OpenAPI Tools API
description: Turn an OpenAPI spec into a typed set of AI SDK tools, one per operation.
icon: "plug"
---

Hand these factories an OpenAPI 3.x spec and they hand back AI SDK tools, one per
operation, with Zod input schemas converted from the spec's JSON schemas and an
`execute(args)` that performs the HTTP call. Drop the result straight into an
agent's `tools`.

Each operation's `summary` / `description` becomes the tool description, so the
agent already knows what each call does.

```ts
import {
  createOpenApiTools,
  createOpenApiToolsSync,
  createOpenApiTool,
  createOpenApiToolSync,
  listOperations,
} from "smithers-orchestrator";
```

<Note>
The async factories (`createOpenApiTools`, `createOpenApiTool`) fetch URL specs.
The `*Sync` variants take only an object or a local file path; they do not fetch
URLs. Pick async when the spec lives behind an HTTP URL.
</Note>

## createOpenApiTools

Build a record of tools from an entire spec, keyed by `operationId`. Async, so it
can load a spec from a URL.

```ts
function createOpenApiTools(
  input: string | OpenApiSpec,
  options?: OpenApiToolsOptions,
): Promise<Record<string, Tool>>;
```

<ParamField path="input" type="string | OpenApiSpec" required>
  The spec as a parsed object, a file path, an HTTP URL, or raw JSON/YAML text.
</ParamField>

<ParamField path="options" type="OpenApiToolsOptions">
  Auth, filtering, base URL, and per-operation curation.

  <Expandable title="OpenApiToolsOptions">
    <ParamField path="baseUrl" type="string">
      Override the request base URL. Defaults to the spec's first
      `servers[].url`.
    </ParamField>
    <ParamField path="headers" type="Record<string, string>">
      Static headers merged into every request.
    </ParamField>
    <ParamField path="auth" type="OpenApiAuth">
      Authentication applied to every request. See [Types](#types).
    </ParamField>
    <ParamField path="include" type="string[]">
      Allowlist of `operationId`s. Only listed operations become tools.
    </ParamField>
    <ParamField path="exclude" type="string[]">
      Blocklist of `operationId`s. If both `include` and `exclude` are set,
      `exclude` wins.
    </ParamField>
    <ParamField path="namePrefix" type="string">
      Prefix added to generated tool names. Does not change the `operationId`
      used for filtering.
    </ParamField>
    <ParamField path="operations" type="Record<string, false | OperationCuration>">
      Per-operation curation keyed by the original `operationId`. Set an entry to
      `false` or `{ include: false }` to skip it, `name` to rename the tool,
      `description` to replace the agent-facing text, and `responseExamples` to
      append concrete response shapes to the description.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="Promise<Record<string, Tool>>" type="object">
  A record of AI SDK tools keyed by `operationId` (or the curated `name`).
</ResponseField>

```ts
import { ToolLoopAgent } from "ai";
import { openai } from "@ai-sdk/openai";
import { createOpenApiTools } from "smithers-orchestrator";

const tools = await createOpenApiTools("https://api.example.com/openapi.json", {
  baseUrl: "https://api.example.com",
  auth: { type: "bearer", token: process.env.API_TOKEN! },
  include: ["listPets", "getPetById"],
});

const agent = new ToolLoopAgent({ model: openai("gpt-5.6-terra"), tools });
```

**Source** [`createOpenApiTools.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/tool-factory/createOpenApiTools.js) · [`OpenApiToolsOptions.ts`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/OpenApiToolsOptions.ts) · **Tests** [`tool-factory.test.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/tests/tool-factory.test.js) · **See also** [OpenAPI tools](/concepts/openapi-tools), [Tools](/integrations/tools)

## createOpenApiToolsSync

Synchronous `createOpenApiTools`. Accepts only a spec object or a local file
path, never a URL. Use it when you can resolve the spec on disk at build time.

```ts
function createOpenApiToolsSync(
  input: string | OpenApiSpec,
  options?: OpenApiToolsOptions,
): Record<string, Tool>;
```

<ParamField path="input" type="string | OpenApiSpec" required>
  A parsed spec object, a local file path, or raw JSON/YAML text. URLs are not
  fetched.
</ParamField>

<ParamField path="options" type="OpenApiToolsOptions">
  Identical to [`createOpenApiTools`](#createopenapitools).
</ParamField>

<ResponseField name="Record<string, Tool>" type="object">
  A record of AI SDK tools keyed by `operationId`.
</ResponseField>

```ts
const tools = createOpenApiToolsSync("./petstore.json", {
  exclude: ["deletePet"],
});
```

**Source** [`createOpenApiToolsSync.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/tool-factory/createOpenApiToolsSync.js) · **Tests** [`tool-factory.test.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/tests/tool-factory.test.js) · **See also** [OpenAPI tools](/concepts/openapi-tools)

## createOpenApiTool / createOpenApiToolSync

Build a single tool from one operation, selected by `operationId`. Same options
as the bulk factories; the only extra argument is the `operationId`.
`createOpenApiTool` is async (fetches URL specs); `createOpenApiToolSync` is
synchronous and object/file-only.

```ts
function createOpenApiTool(
  input: string | OpenApiSpec,
  operationId: string,
  options?: OpenApiToolsOptions,
): Promise<Tool>;

function createOpenApiToolSync(
  input: string | OpenApiSpec,
  operationId: string,
  options?: OpenApiToolsOptions,
): Tool;
```

<ParamField path="input" type="string | OpenApiSpec" required>
  The spec. `createOpenApiTool` accepts a URL; `createOpenApiToolSync` does not.
</ParamField>

<ParamField path="operationId" type="string" required>
  The `operationId` of the operation to turn into a tool.
</ParamField>

<ParamField path="options" type="OpenApiToolsOptions">
  Same shape as [`createOpenApiTools`](#createopenapitools). `include` /
  `exclude` are ignored here since one operation is named directly.
</ParamField>

<ResponseField name="Tool" type="object">
  A single AI SDK tool. `createOpenApiTool` returns a `Promise<Tool>`.
</ResponseField>

```ts
const getPet = await createOpenApiTool("./petstore.json", "getPetById", {
  auth: { type: "apiKey", name: "X-API-Key", in: "header", value: KEY },
});
```

**Source** [`createOpenApiTool.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/tool-factory/createOpenApiTool.js) · [`createOpenApiToolSync.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/tool-factory/createOpenApiToolSync.js) · **Tests** [`tool-factory.test.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/tests/tool-factory.test.js) · **See also** [Tools](/integrations/tools)

## listOperations

Introspect a spec without building any tools. Returns one entry per operation,
useful for auditing what an agent would be able to call before wiring it up.

```ts
function listOperations(input: string | OpenApiSpec): Array<{
  operationId: string;
  method: string;
  path: string;
  summary: string;
}>;
```

<ParamField path="input" type="string | OpenApiSpec" required>
  A parsed spec object, a local file path, or raw JSON/YAML text.
</ParamField>

<ResponseField name="Array<OperationSummary>" type="array">
  One entry per operation.

  <Expandable title="OperationSummary">
    <ResponseField name="operationId" type="string">
      The operation's `operationId`, the key tools are generated under.
    </ResponseField>
    <ResponseField name="method" type="string">
      HTTP method (`get`, `post`, `put`, `delete`, `patch`).
    </ResponseField>
    <ResponseField name="path" type="string">
      The path template, e.g. `/pets/{id}`.
    </ResponseField>
    <ResponseField name="summary" type="string">
      The operation's `summary`, or an empty string when absent.
    </ResponseField>
  </Expandable>
</ResponseField>

```ts
for (const op of listOperations("./petstore.json")) {
  console.log(`${op.method.toUpperCase()} ${op.path} → ${op.operationId}`);
}
```

The same preview is available from the CLI:

```bash
bunx smithers-orchestrator openapi list ./api/openapi.yaml
```

**Source** [`listOperations.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/tool-factory/listOperations.js) · **Tests** [`spec-parser.test.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/tests/spec-parser.test.js) · **See also** [OpenAPI tools](/concepts/openapi-tools)

## Types

`OpenApiAuth`, `OpenApiSpec`, and `OpenApiToolsOptions` are exported from
`smithers-orchestrator`. `Tool` is the AI SDK tool type from the `ai` package.

### OpenApiAuth

Applied to every request. A discriminated union on `type`.

<ResponseField name="OpenApiAuth" type="union">
  <Expandable title='type: "apiKey"'>
    <ResponseField name="name" type="string" required>
      Header or query-parameter name carrying the key.
    </ResponseField>
    <ResponseField name="value" type="string" required>
      The API key value.
    </ResponseField>
    <ResponseField name="in" type='"header" | "query"' required>
      Where to place the key.
    </ResponseField>
  </Expandable>
  <Expandable title='type: "bearer"'>
    <ResponseField name="token" type="string" required>
      Sent as `Authorization: Bearer <token>`.
    </ResponseField>
  </Expandable>
  <Expandable title='type: "basic"'>
    <ResponseField name="username" type="string" required>
      Basic-auth username.
    </ResponseField>
    <ResponseField name="password" type="string" required>
      Basic-auth password.
    </ResponseField>
  </Expandable>
</ResponseField>

```ts
import type { OpenApiAuth } from "smithers-orchestrator";

const apiKey: OpenApiAuth = { type: "apiKey", name: "X-API-Key", in: "header", value: KEY };
const bearer: OpenApiAuth = { type: "bearer", token: TOKEN };
const basic: OpenApiAuth = { type: "basic", username: USER, password: PASS };
```

### OpenApiSpec

The parsed OpenAPI 3.x document shape accepted as an object `input`. Most callers
pass a file path or URL string instead and let the loader parse it, but you can
import the type to construct or narrow a spec yourself.

```ts
import type { OpenApiSpec } from "smithers-orchestrator";

type OpenApiSpec = {
  openapi: string;
  info: { title: string; version: string; description?: string };
  servers?: Array<{ url: string; description?: string }>;
  paths: Record<string, OpenApiPathItem>;
  components?: { schemas?: Record<string, OpenApiSchemaObject>; /* ... */ };
};
```

See the [Types reference](/reference/types) for the full `OpenApiSpec`,
`OpenApiPathItem`, and `OpenApiSchemaObject` shapes.

**Source** [`OpenApiAuth.ts`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/OpenApiAuth.ts) · [`OpenApiSpec.ts`](https://github.com/smithersai/smithers/blob/main/packages/openapi/src/OpenApiSpec.ts) · **Tests** [`spec-parser.test.js`](https://github.com/smithersai/smithers/blob/main/packages/openapi/tests/spec-parser.test.js) · **See also** [Types](/reference/types), [OpenAPI tools](/concepts/openapi-tools)

---

For request/response handling, filtering semantics, observability metrics, and
current limitations (cookie params, non-JSON bodies, Swagger 2.0), see the
[OpenAPI tools concept](/concepts/openapi-tools). For wiring tools into agents,
see [Tools](/integrations/tools).
