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

# Create a tool set

> Point a tool set at an MCP server, an OpenAPI spec, an HTTP API, or nothing at all. Cadenya syncs the tools it finds.

A tool set is a collection of tools that share one provider. You supply an adapter, Cadenya discovers the tools behind it, and any [agent variation](/docs/guides/sdk/agents#assignments-tools-sub-agents-memory) you assign the set to can call them.

The request has two required fields, `metadata` and `spec`, and the whole story lives in `spec.adapter`.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const toolSet = await client.toolSets.create({
    workspaceId,
    metadata: { name: 'Faker', externalId: 'faker' },
    spec: {
      adapter: {
        type: 'mcp',
        mcp: { url: 'https://free.cadenya.com/faker-mcp' },
      },
    },
  });

  console.log(toolSet.state); // STATE_ACTIVE
  ```

  ```go Go theme={null}
  toolSet, err := client.ToolSets.New(ctx, cadenya.ToolSetNewParams{
  	WorkspaceID: cadenya.String(workspaceID),
  	Metadata: shared.CreateResourceMetadataParam{
  		Name:       "Faker",
  		ExternalID: cadenya.String("faker"),
  	},
  	Spec: cadenya.ToolSetSpecParam{
  		Adapter: cadenya.ToolSetAdapterParamOfMCP(cadenya.ToolSetAdapterMCPParam{
  			URL: cadenya.String("https://free.cadenya.com/faker-mcp"),
  		}),
  	},
  })

  fmt.Println(toolSet.State) // STATE_ACTIVE
  ```

  ```ruby Ruby theme={null}
  tool_set = cadenya.tool_sets.create(
    workspace_id: workspace_id,
    metadata: {name: "Faker", external_id: "faker"},
    spec: {adapter: {type: :mcp, mcp: {url: "https://free.cadenya.com/faker-mcp"}}}
  )

  puts(tool_set.state) # STATE_ACTIVE
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.cadenya.com/v1/workspaces/${WORKSPACE_ID}/tool_sets" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{
      "metadata": { "name": "Faker", "externalId": "faker" },
      "spec": { "adapter": { "type": "mcp", "mcp": { "url": "https://free.cadenya.com/faker-mcp" } } }
    }'
  ```
</CodeGroup>

## Pick an adapter

Four kinds. Set exactly one.

| Adapter   | Points at                       | Tools come from                     |
| --------- | ------------------------------- | ----------------------------------- |
| `mcp`     | A Model Context Protocol server | The server's tool list              |
| `openapi` | An OpenAPI spec, fetched by URL | One tool per operation              |
| `http`    | A REST API base URL             | Tools you define by hand            |
| `bare`    | Nothing                         | Tools you define, calls you fulfill |

<Note>
  The adapter is a discriminated union: `type` names the variant, and the key matching `type` carries the payload. Both are required, and the SDKs type it as a tagged union, so TypeScript narrows on `type` and Go offers one constructor per variant.
</Note>

<CodeGroup>
  ```typescript MCP theme={null}
  const toolSet = await client.toolSets.create({
    workspaceId,
    metadata: { name: 'Faker', externalId: 'faker' },
    spec: {
      adapter: {
        type: 'mcp',
        mcp: { url: 'https://free.cadenya.com/faker-mcp' },
      },
    },
  });

  console.log(toolSet.state); // STATE_ACTIVE
  ```

  ```typescript OpenAPI theme={null}
  const toolSet = await client.toolSets.create({
    workspaceId,
    metadata: { name: 'Petstore', externalId: 'petstore' },
    spec: {
      adapter: {
        type: 'openapi',
        openapi: {
          type: 'url',
          url: 'https://petstore3.swagger.io/api/v3/openapi.json',
          headers: { Authorization: 'Bearer ${PETSTORE_TOKEN}' },
        },
      },
    },
  });
  // Every operation in the spec becomes a tool. Petstore yields 19.
  ```

  ```typescript HTTP theme={null}
  const toolSet = await client.toolSets.create({
    workspaceId,
    metadata: { name: 'Orders API', externalId: 'orders' },
    spec: {
      adapter: {
        type: 'http',
        http: {
          baseUrl: 'https://api.example.com',
          headers: { Authorization: 'Bearer ${EXAMPLE_TOKEN}' },
        },
      },
    },
  });
  // No tools yet. Define them yourself against the base URL.
  ```

  ```typescript Bare theme={null}
  const toolSet = await client.toolSets.create({
    workspaceId,
    metadata: { name: 'Human approvals', externalId: 'human' },
    spec: {
      adapter: {
        type: 'bare',
        bare: {},
      },
    },
  });
  // Nothing executes. Your code answers each call.
  ```
</CodeGroup>

The call returns immediately with `state: STATE_ACTIVE`. Discovery happens in the background, so `info.toolCount` reads `0` for a moment even when the provider has tools waiting.

## Watch the sync

There is no public sync endpoint. Cadenya syncs when you create or update the adapter. Synced MCP sources and OpenAPI specifications fetched by URL also refresh hourly. The only way to know a sync landed is the event stream.

```typescript theme={null}
const events = await client.toolSets.listEvents(toolSet.metadata.id, { workspaceId });
for await (const event of events) {
  console.log(event.event?.type, event.event?.type === 'syncCompleted' ? event.event.syncCompleted.toolsSynced : undefined);
  // syncStarted    undefined
  // syncCompleted  3
}
```

Three event types: `syncStarted`, `syncCompleted` (carries `toolsSynced`), and `syncFailed` (carries `message` and `errorType`). Poll `listEvents` after a create when your setup script needs to block until the tools exist. `info.lastSync` gives you the timestamp of the most recent *successful* sync (it is omitted until one lands). `info` returns on every read; `includeInfo` is a no-op on tool sets.

<Warning>
  An MCP adapter with `justInTime.enabled` set to `true` syncs **nothing** up front. Tools load when an objective starts, and `info.toolCount` stays at `0`. That is the point of on-demand discovery, and it surprises anyone waiting for a tool count to climb.
</Warning>

## Keep secrets out of the request

Adapter headers take `${SECRET_NAME}` placeholders. Cadenya resolves them at call time and the plaintext never comes back on a read.

```typescript theme={null}
// 1. Create the tool set with a placeholder, not a token.
const toolSet = await client.toolSets.create({
  workspaceId,
  metadata: { name: 'Orders API', externalId: 'orders' },
  spec: {
    adapter: {
      type: 'http',
      http: {
        baseUrl: 'https://api.example.com',
        headers: { Authorization: 'Bearer ${EXAMPLE_TOKEN}' },
      },
    },
  },
});

// 2. Store the value on the tool set.
await client.toolSets.secrets.create(toolSet.metadata.id, {
  workspaceId,
  metadata: { name: 'EXAMPLE_TOKEN' },
  spec: { value: process.env['EXAMPLE_TOKEN']! },
});
```

Read the secret back and `spec.value` is an empty string. Names resolve in order: [objective secrets](/docs/api-reference/objectiveservice/create-a-new-objective), then tool set secrets, then [workspace secrets](/docs/guides/secrets). The narrowest scope wins, which is how a per-user token overrides a service credential for one run.

## Filter what syncs

MCP and OpenAPI adapters take `includeTools` and `excludeTools`. A filter is a list of attribute matchers joined by `OPERATOR_AND` or `OPERATOR_OR`.

```typescript theme={null}
await client.toolSets.create({
  workspaceId,
  metadata: { name: 'Faker', externalId: 'faker' },
  spec: {
    adapter: {
      type: 'mcp',
      mcp: {
        url: 'https://free.cadenya.com/faker-mcp',
        excludeTools: {
          operator: 'OPERATOR_AND',
          filters: [
            {
              attribute: 'ATTRIBUTE_NAME',
              matcher: { type: 'contains', contains: 'Curse', caseSensitive: false },
            },
          ],
        },
        toolApprovals: { type: 'always', always: true },
      },
    },
  },
});
```

Match on `ATTRIBUTE_NAME`, `ATTRIBUTE_TITLE`, or `ATTRIBUTE_DESCRIPTION`. The `matcher` is its own union: `type` picks `exact`, `contains`, `startsWith`, `endsWith`, or `regex`, the matching key carries the string, and `caseSensitive` rides alongside. `toolApprovals` puts every synced tool behind [human approval](/docs/guides/callbacks/approving-a-tool), either `always` or for the subset an `only` filter selects.

Filters apply on every sync, not once. Restore a tool the filter excludes and the next sync omits it again.

## Define tools by hand

An `http` or `bare` tool set starts empty. Create tools on it with `spec.config` naming the same adapter kind as the parent set.

<CodeGroup>
  ```typescript HTTP tool theme={null}
  await client.toolSets.tools.create(toolSet.metadata.id, {
    workspaceId,
    metadata: { name: 'get_order' },
    spec: {
      description: 'Fetch an order by id.',
      requiresApproval: false,
      parameters: {
        type: 'object',
        properties: { orderId: { type: 'string' } },
        required: ['orderId'],
      },
      config: {
        type: 'http',
        http: { requestMethod: 'GET', path: '/orders/{orderId}' },
      },
    },
  });
  ```

  ```typescript Bare tool theme={null}
  await client.toolSets.tools.create(toolSet.metadata.id, {
    workspaceId,
    metadata: { name: 'issue_refund' },
    spec: {
      description: 'Refund a customer order.',
      requiresApproval: true,
      parameters: {
        type: 'object',
        properties: { orderId: { type: 'string' }, amount: { type: 'number' } },
        required: ['orderId'],
      },
      config: { type: 'bare', bare: {} },
    },
  });
  ```
</CodeGroup>

Four fields are required on a tool spec: `description`, `parameters` (a JSON Schema), `requiresApproval`, and `config`. All four are enforced, so a misspelled `inputSchema` or a missing `config` is a `400` rather than a tool the agent can never call correctly.

The response adds `llmToolName`, a cleaned-up name Cadenya derives for the model: `issue_refund` becomes `IssueRefund`.

## Bare tools: your code is the runtime

A bare tool call fires nothing. The objective parks, the tool call sits at `TOOL_CALL_EXECUTION_STATUS_WAITING_FOR_CONTENT`, and your code answers it.

```typescript theme={null}
// Somewhere in your worker: find the parked call and fulfill it.
const parked = await client.objectives.toolCalls.list(objectiveId, {
  workspaceId,
  executionStatus: 'TOOL_CALL_EXECUTION_STATUS_WAITING_FOR_CONTENT',
});

for await (const call of parked) {
  const result = await refundOrder(call.data.arguments);

  await client.objectives.toolCalls.setContent(objectiveId, call.metadata.id, {
    workspaceId,
    content: [{ type: 'text', text: { text: JSON.stringify(result) } }],
  });
}
```

That unlocks two patterns. **Human in the loop:** park the call, show it to a person, submit their answer. **Reverse harness:** run the tool on your own infrastructure, inside your VPC, and report the result back. Cadenya never needs a route into your network.

Set `contentTimeout` on the bare adapter to bound the wait. Leave it unset and the call waits 24 hours, then resolves on its own with a synthesized system result saying no content arrived. The objective keeps going either way.

## Lifecycle

Tool sets are created `STATE_ACTIVE` and archive rather than delete when they are still in use.

```typescript theme={null}
await client.toolSets.archive(toolSet.metadata.id, { workspaceId });   // stop syncing, keep history
await client.toolSets.unarchive(toolSet.metadata.id, { workspaceId }); // resume on the next cycle
await client.toolSets.delete(toolSet.metadata.id, { workspaceId });    // gone; fails if assigned
```

Archiving stops the sync, hides the set from lists, and pulls its tools from objectives, while leaving variation assignments and history intact. Delete refuses to run while the set is assigned to a variation. Individual tools follow the same idea with `omit` and `restore`: an omitted tool stays in the set but no agent sees it.

## Next steps

<CardGroup cols={2}>
  <Card title="Connect an MCP server" icon="plug" href="/docs/guides/tool-sets/mcp">
    The hands-on lesson, from server URL to an agent calling the tools.
  </Card>

  <Card title="Import an OpenAPI spec" icon="file-code" href="/docs/guides/tool-sets/openapi">
    Turn an existing REST API into a tool set, one operation at a time.
  </Card>

  <Card title="Approve a tool call" icon="hand" href="/docs/guides/callbacks/approving-a-tool">
    Park a dangerous call, ask a person, then let the objective continue.
  </Card>

  <Card title="Store and use secrets" icon="key" href="/docs/guides/store-and-use-secrets">
    Where `${SECRET_NAME}` resolves from, and which scope wins.
  </Card>
</CardGroup>


## OpenAPI

````yaml post /v1/workspaces/{workspaceId}/tool_sets
openapi: 3.1.0
info:
  title: Cadenya API
  description: API for the Cadenya Agent Runtime platform.
  version: '1.0'
servers:
  - url: https://api.cadenya.com
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: AIProviderKeyService
  - name: APIKeyService
    description: |-
      Issue, rotate, disable, and revoke a workspace's API keys. Every key
       belongs to exactly one workspace; the system-managed global account key is
       managed via GlobalAPIKeyService instead.
  - name: AccountService
    description: >-
      Manage the authenticated account. Accounts are the top-level
      organizational
       unit and contain one or more workspaces.
  - name: AgentScheduleService
    description: >-
      Manage recurring schedules attached to agents. Schedules trigger
      objectives
       on a cadence defined by AgentScheduleSpec.Schedule.
  - name: AgentService
    description: >-
      Manage AI agents within a workspace. Agents define AI behavior and tool
      access.
  - name: AgentVariationService
    description: >-
      Manage variations of an agent and their tool, sub-agent, and memory layer
      assignments.
  - name: GlobalAPIKeyService
    description: |-
      Manage the account's system-provisioned global API key. The global key is
       the only key that spans every workspace; it is created by the system and
       cannot be deleted, so the surface is retrieve, rotate, and the
       disable/enable kill switch.
  - name: MemoryService
    description: >-
      Manage memory layers and their entries. Layers are named containers that
      can
       be composed into an objective's memory cascade; entries are the keyed values
       within a layer. System-managed layers (e.g., episodic layers created by the
       runtime) cannot be mutated through this API.
  - name: ModelService
    description: |-
      Manage LLM models available to a workspace. Models represent provider and
       family pairs (e.g., "anthropic/claude-sonnet-4.6"). Workspaces are seeded
       with the supported models and you can enable or disable each one.
  - name: ObjectiveEventStreamsService
  - name: ObjectiveService
  - name: ProfilesService
    description: |-
      Operations on profiles, the account-level principals (users, API keys,
       system) that authenticate against the API.
  - name: SearchService
  - name: TenantService
    description: >-
      Read and erase tenants and the subjects under them. Tenants and subjects
      are
       created by assertion — on objective creation or widget session mint — never
       directly, so this service has no create or update: it exists to enumerate what
       assertions have produced, and to destroy it on request.
  - name: ToolService
    description: >-
      Manage tool sets and the tools they contain. Tool sets group related
      tools,
       and tools define specific capabilities available to agents.

       When a tool set is managed, only API key actors can modify its tools; human
       (profile) actors cannot.
  - name: UploadService
    description: |-
      Issue short-lived presigned URLs for direct client-to-object-storage
       uploads. Created uploads can be referenced by id when creating or updating
       resources that accept binary content (e.g., MemoryEntry).
  - name: WidgetService
    description: |-
      Manage embeddable chat widgets. A widget binds an agent to a globally
       unique hostname with a per-widget origin allowlist; browsers reach it with
       session tokens minted via WidgetSessionService.
  - name: WidgetSessionService
    description: >-
      Mint and manage widget sessions. Session creation is server-to-server
      only:
       the customer's backend authenticates its visitor, asserts tenant/subject
       context, attaches any per-visitor secrets, and receives a short-lived
       bearer token the browser uses against the widget host.
  - name: WorkspaceAdminService
    description: >-
      Administer workspaces across the account: create and archive workspaces
      and
       manage their membership. These operations are account-scoped and require the
       admin role (a token whose profile holds the WorkOS admin role); they live
       under /v1/account/workspaces rather than the workspace-scoped /v1/workspaces
       tree so an admin can manage any workspace in the account, including ones they
       are not themselves a member of.
  - name: WorkspaceSecretService
  - name: WorkspaceService
    description: |-
      Manage workspaces within an account. Workspaces provide organizational
       grouping and isolation for resources such as agents, tools, and API keys.

       This is the workspace-scoped, end-user surface. Administrative operations
       (create / archive workspaces, manage members) live in WorkspaceAdminService
       under /v1/account/workspaces and require the admin role.
paths:
  /v1/workspaces/{workspaceId}/tool_sets:
    post:
      tags:
        - ToolService
        - Tool Sets
      summary: Create a new tool set
      description: Creates a new tool set in the workspace
      operationId: ToolService_CreateToolSet
      parameters:
        - name: workspaceId
          in: path
          description: Workspace ID.
          required: true
          schema:
            type: string
            example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateToolSetRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ToolSet'
        default:
          description: Default error response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
      x-codeSamples:
        - lang: JavaScript
          source: |-
            import Cadenya from '@cadenya/cadenya';

            const client = new Cadenya({
              apiKey: process.env['CADENYA_API_KEY'], // This is the default and can be omitted
            });

            const toolSet = await client.toolSets.create({
              workspaceId: 'workspace_01HXKD2E5NQM3T9AYWCF133E3Q',
              metadata: { name: 'name' },
              spec: {},
            });

            console.log(toolSet.metadata);
        - lang: Python
          source: |-
            import os
            from cadenya import Cadenya

            client = Cadenya(
                api_key=os.environ.get("CADENYA_API_KEY"),  # This is the default and can be omitted
            )
            tool_set = client.tool_sets.create(
                workspace_id="workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
                metadata={
                    "name": "name"
                },
                spec={},
            )
            print(tool_set.metadata)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go.cadenya.com/cadenya-go\"\n\t\"go.cadenya.com/cadenya-go/option\"\n\t\"go.cadenya.com/cadenya-go/shared\"\n)\n\nfunc main() {\n\tclient := cadenya.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\ttoolSet, err := client.ToolSets.New(context.TODO(), cadenya.ToolSetNewParams{\n\t\tWorkspaceID: cadenya.String(\"workspace_01HXKD2E5NQM3T9AYWCF133E3Q\"),\n\t\tMetadata: shared.CreateResourceMetadataParam{\n\t\t\tName: \"name\",\n\t\t},\n\t\tSpec: cadenya.ToolSetSpecParam{},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", toolSet.Metadata)\n}\n"
        - lang: Ruby
          source: |-
            require "cadenya"

            cadenya = Cadenya::Client.new(api_key: "My API Key")

            tool_set = cadenya.tool_sets.create(
              workspace_id: "workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
              metadata: {name: "name"},
              spec: {}
            )

            puts(tool_set)
        - lang: CLI
          source: |-
            cadenya tool-sets create \
              --api-key 'My API Key' \
              --workspace-id workspace_01HXKD2E5NQM3T9AYWCF133E3Q \
              --metadata '{name: name}' \
              --spec '{}'
components:
  schemas:
    CreateToolSetRequest:
      required:
        - metadata
        - spec
      type: object
      properties:
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: Workspace ID.
        metadata:
          $ref: '#/components/schemas/CreateResourceMetadata'
        spec:
          $ref: '#/components/schemas/ToolSetSpec'
    ToolSet:
      required:
        - metadata
        - spec
        - state
      type: object
      properties:
        metadata:
          $ref: '#/components/schemas/ResourceMetadata'
        spec:
          $ref: '#/components/schemas/ToolSetSpec'
        info:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ToolSetInfo'
          description: Tool set information
        state:
          readOnly: true
          enum:
            - STATE_UNSPECIFIED
            - STATE_ACTIVE
            - STATE_ARCHIVED
          type: string
          description: >-
            The current lifecycle state of the tool set. Output only. Tool sets
            are
             created STATE_ACTIVE; use the :archive and :unarchive actions to
             transition between states.
          format: enum
    Status:
      type: object
      properties:
        code:
          type: integer
          description: >-
            The status code, which should be an enum value of
            [google.rpc.Code][google.rpc.Code].
          format: int32
        message:
          type: string
          description: >-
            A developer-facing error message, which should be in English. Any
            user-facing error message should be localized and sent in the
            [google.rpc.Status.details][google.rpc.Status.details] field, or
            localized by the client.
        details:
          type: array
          items:
            $ref: '#/components/schemas/GoogleProtobufAny'
          description: >-
            A list of messages that carry the error details.  There is a common
            set of message types for APIs to use.
      description: >-
        The `Status` type defines a logical error model that is suitable for
        different programming environments, including REST APIs and RPC APIs. It
        is used by [gRPC](https://github.com/grpc). Each `Status` message
        contains three pieces of data: error code, error message, and error
        details. You can find out more about this error model and how to work
        with it in the [API Design
        Guide](https://cloud.google.com/apis/design/errors).
    CreateResourceMetadata:
      required:
        - name
      type: object
      properties:
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
      description: |-
        CreateResourceMetadata contains the user-provided fields for creating
         a workspace-scoped resource. Read-only fields (id, account_id, workspace_id, profile_id,
         created_at) are excluded since they are set by the server.
    ToolSetSpec:
      type: object
      properties:
        description:
          type: string
        adapter:
          $ref: '#/components/schemas/ToolSetAdapter'
    ResourceMetadata:
      required:
        - id
        - accountId
        - workspaceId
        - name
        - profileId
        - createdAt
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the resource (prefixed ULID, e.g.,
            "agent_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this resource belongs to for multi-tenant isolation
            (prefixed ULID)
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: >-
            Workspace this resource belongs to for organizational grouping
            (prefixed ULID)
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
             Required for resources that users interact with directly
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
          description: ID of the actor (user or service account) that created this resource
        createdAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was created
          format: date-time
        updatedAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was last updated
          format: date-time
      description: >-
        Standard metadata for persistent, named resources (e.g., agents, tools,
        prompts)
    ToolSetInfo:
      type: object
      properties:
        toolCount:
          readOnly: true
          type: integer
          format: int32
        agentCount:
          readOnly: true
          type: integer
          format: int32
        lastSync:
          readOnly: true
          type: string
          format: date-time
        createdBy:
          $ref: '#/components/schemas/Profile'
        availableTools:
          type: integer
          format: int32
        omittedTools:
          type: integer
          format: int32
    GoogleProtobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: The type of the serialized message.
      additionalProperties: true
      description: >-
        Contains an arbitrary serialized message along with a @type that
        describes the type of the serialized message.
    ToolSetAdapter:
      oneOf:
        - $ref: '#/components/schemas/ToolSetAdapter_McpVariant'
        - $ref: '#/components/schemas/ToolSetAdapter_HttpVariant'
        - $ref: '#/components/schemas/ToolSetAdapter_OpenapiVariant'
        - $ref: '#/components/schemas/ToolSetAdapter_BareVariant'
      discriminator:
        propertyName: type
        mapping:
          mcp:
            $ref: '#/components/schemas/ToolSetAdapter_McpVariant'
          http:
            $ref: '#/components/schemas/ToolSetAdapter_HttpVariant'
          openapi:
            $ref: '#/components/schemas/ToolSetAdapter_OpenapiVariant'
          bare:
            $ref: '#/components/schemas/ToolSetAdapter_BareVariant'
    Profile:
      required:
        - metadata
        - spec
      type: object
      properties:
        metadata:
          $ref: '#/components/schemas/AccountResourceMetadata'
        spec:
          $ref: '#/components/schemas/ProfileSpec'
      description: |-
        A profile identifies a user or non-human principal (such as an API key)
         at the account level. Profiles are account-scoped and can be granted access
         to multiple workspaces.
    ToolSetAdapter_McpVariant:
      type: object
      required:
        - type
        - mcp
      properties:
        type:
          type: string
          enum:
            - mcp
        mcp:
          $ref: '#/components/schemas/ToolSetAdapter_MCP'
    ToolSetAdapter_HttpVariant:
      type: object
      required:
        - type
        - http
      properties:
        type:
          type: string
          enum:
            - http
        http:
          $ref: '#/components/schemas/ToolSetAdapter_HTTP'
    ToolSetAdapter_OpenapiVariant:
      type: object
      required:
        - type
        - openapi
      properties:
        type:
          type: string
          enum:
            - openapi
        openapi:
          $ref: '#/components/schemas/ToolSetAdapter_OpenAPI'
    ToolSetAdapter_BareVariant:
      type: object
      required:
        - type
        - bare
      properties:
        type:
          type: string
          enum:
            - bare
        bare:
          $ref: '#/components/schemas/ToolSetAdapter_Bare'
    AccountResourceMetadata:
      required:
        - id
        - accountId
        - name
        - profileId
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the resource (prefixed ULID, e.g.,
            "apikey_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this resource belongs to for multi-tenant isolation
            (prefixed ULID)
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
             Required for resources that users interact with directly
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
        createdAt:
          readOnly: true
          type: string
          format: date-time
      description: >-
        AccountResourceMetadata is used to represent a resource that is
        associated to an account but not to a workspace.
    ProfileSpec:
      required:
        - type
      type: object
      properties:
        email:
          type: string
          description: >-
            Email address of the profile. Required and unique within an account
            for
             user profiles.
        name:
          type: string
          description: Display name (e.g., "Bobby Tables").
        type:
          enum:
            - PROFILE_TYPE_UNSPECIFIED
            - PROFILE_TYPE_USER
            - PROFILE_TYPE_API_KEY
            - PROFILE_TYPE_SYSTEM
          type: string
          description: >-
            Whether this profile represents a human user, an API key, or a
            system
             principal.
          format: enum
      description: Configuration for a profile.
    ToolSetAdapter_MCP:
      type: object
      properties:
        url:
          type: string
        headers:
          type: object
          additionalProperties:
            type: string
        includeTools:
          allOf:
            - $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
          description: Include/exclude with flat filters
        excludeTools:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
        toolApprovals:
          allOf:
            - $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter'
          description: >-
            Setting for how to assign tool approval requirements when they are
            synced from an MCP server
        justInTime:
          allOf:
            - $ref: '#/components/schemas/ToolSetAdapter_JustInTime'
          description: |-
            When enabled, tools are loaded from the MCP server just-in-time at
             objective creation using the objective's resolved secrets, instead of
             being synced ahead of time. Just-in-time tool sets are excluded from
             the background sync system.
    ToolSetAdapter_HTTP:
      type: object
      properties:
        baseUrl:
          type: string
        headers:
          type: object
          additionalProperties:
            type: string
    ToolSetAdapter_OpenAPI:
      oneOf:
        - $ref: '#/components/schemas/ToolSetAdapter_OpenAPI_Url'
        - $ref: '#/components/schemas/ToolSetAdapter_OpenAPI_UploadId'
      discriminator:
        propertyName: type
        mapping:
          url:
            $ref: '#/components/schemas/ToolSetAdapter_OpenAPI_Url'
          uploadId:
            $ref: '#/components/schemas/ToolSetAdapter_OpenAPI_UploadId'
    ToolSetAdapter_Bare:
      type: object
      properties:
        contentTimeout:
          pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$
          type: integer
          description: |-
            How long to wait for content to be set before the tool call errors.
             If unset, the call waits indefinitely.
      description: |-
        Bare tool sets define tools without an execution adapter. A bare tool
         call doesn't fire anything: the objective's workflow pauses and waits
         for an external API consumer to set the tool call's content (e.g.
         human-in-the-loop tools, or a reverse harness that polls for pending
         tool calls, executes locally, and reports results back via
         SetToolCallContent).
    ToolSetAdapter_ToolFilter:
      required:
        - operator
      type: object
      properties:
        filters:
          type: array
          items:
            $ref: '#/components/schemas/ToolSetAdapter_AttributeFilter'
        operator:
          enum:
            - OPERATOR_UNSPECIFIED
            - OPERATOR_AND
            - OPERATOR_OR
            - OPERATOR_AND
            - OPERATOR_OR
          type: string
          format: enum
      description: Top-level filter with simple boolean logic (no nesting)
    ToolSetAdapter_ApprovalRequirementFilter:
      oneOf:
        - $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter_Always'
        - $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter_Only'
      discriminator:
        propertyName: type
        mapping:
          always:
            $ref: >-
              #/components/schemas/ToolSetAdapter_ApprovalRequirementFilter_Always
          only:
            $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter_Only'
      description: >-
        Approval filters that will automatically set the approval requirement on
        tools synced from an external source
    ToolSetAdapter_JustInTime:
      type: object
      properties:
        enabled:
          type: boolean
        failObjectiveOnToolListError:
          type: boolean
          description: >-
            If set, an objective will automatically be failed if tools cannot be
            loaded
             in the initial stages of an objective being created. Tools are loaded asynchronously,
             so this setting is useful for ensuring that an objective continued any further if tools are not available.
      description: 'Defines behavior for just-in-time capable tool set adapters (IE: MCP).'
    ToolSetAdapter_OpenAPI_Url:
      type: object
      required:
        - type
        - url
      properties:
        type:
          type: string
          enum:
            - url
        url:
          type: string
          description: URL to fetch the OpenAPI spec from. Synced automatically every hour.
        headers:
          type: object
          additionalProperties:
            type: string
          description: >-
            Headers sent when fetching the spec from a URL and when dispatching
            tool calls.
        includeTools:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
        excludeTools:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
        toolApprovals:
          $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter'
        baseUrl:
          type: string
          description: |-
            Base URL for dispatching tool calls. If set, overrides the server
             resolved from the spec's servers array.
        serverName:
          type: string
          description: |-
            Name of the server entry in the spec's servers array (OpenAPI 3.2
             server.name field). Used to select which server URL to dispatch to
             when base_url is not set. If unset, the first server is used.
             Ignored when base_url is set.
    ToolSetAdapter_OpenAPI_UploadId:
      type: object
      required:
        - type
        - uploadId
      properties:
        type:
          type: string
          enum:
            - uploadId
        uploadId:
          example: upload_01HXKD2E5NQM3T9AYWCFZ05DNK
          type: string
          description: ID of a COMPLETE Upload containing the OpenAPI spec document.
        headers:
          type: object
          additionalProperties:
            type: string
          description: >-
            Headers sent when fetching the spec from a URL and when dispatching
            tool calls.
        includeTools:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
        excludeTools:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
        toolApprovals:
          $ref: '#/components/schemas/ToolSetAdapter_ApprovalRequirementFilter'
        baseUrl:
          type: string
          description: |-
            Base URL for dispatching tool calls. If set, overrides the server
             resolved from the spec's servers array.
        serverName:
          type: string
          description: |-
            Name of the server entry in the spec's servers array (OpenAPI 3.2
             server.name field). Used to select which server URL to dispatch to
             when base_url is not set. If unset, the first server is used.
             Ignored when base_url is set.
    ToolSetAdapter_AttributeFilter:
      required:
        - attribute
      type: object
      properties:
        attribute:
          enum:
            - ATTRIBUTE_UNSPECIFIED
            - ATTRIBUTE_NAME
            - ATTRIBUTE_TITLE
            - ATTRIBUTE_DESCRIPTION
            - ATTRIBUTE_NAME
            - ATTRIBUTE_TITLE
            - ATTRIBUTE_DESCRIPTION
          type: string
          format: enum
        matcher:
          $ref: '#/components/schemas/ToolSetAdapter_StringMatcher'
      description: Single attribute filter
    ToolSetAdapter_ApprovalRequirementFilter_Always:
      type: object
      required:
        - type
        - always
      properties:
        type:
          type: string
          enum:
            - always
        always:
          type: boolean
    ToolSetAdapter_ApprovalRequirementFilter_Only:
      type: object
      required:
        - type
        - only
      properties:
        type:
          type: string
          enum:
            - only
        only:
          $ref: '#/components/schemas/ToolSetAdapter_ToolFilter'
    ToolSetAdapter_StringMatcher:
      oneOf:
        - $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Exact'
        - $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_StartsWith'
        - $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_EndsWith'
        - $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Contains'
        - $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Regex'
      discriminator:
        propertyName: type
        mapping:
          exact:
            $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Exact'
          startsWith:
            $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_StartsWith'
          endsWith:
            $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_EndsWith'
          contains:
            $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Contains'
          regex:
            $ref: '#/components/schemas/ToolSetAdapter_StringMatcher_Regex'
      description: String matching operations
    ToolSetAdapter_StringMatcher_Exact:
      type: object
      required:
        - type
        - exact
      properties:
        type:
          type: string
          enum:
            - exact
        exact:
          type: string
        caseSensitive:
          type: boolean
    ToolSetAdapter_StringMatcher_StartsWith:
      type: object
      required:
        - type
        - startsWith
      properties:
        type:
          type: string
          enum:
            - startsWith
        startsWith:
          type: string
        caseSensitive:
          type: boolean
    ToolSetAdapter_StringMatcher_EndsWith:
      type: object
      required:
        - type
        - endsWith
      properties:
        type:
          type: string
          enum:
            - endsWith
        endsWith:
          type: string
        caseSensitive:
          type: boolean
    ToolSetAdapter_StringMatcher_Contains:
      type: object
      required:
        - type
        - contains
      properties:
        type:
          type: string
          enum:
            - contains
        contains:
          type: string
        caseSensitive:
          type: boolean
    ToolSetAdapter_StringMatcher_Regex:
      type: object
      required:
        - type
        - regex
      properties:
        type:
          type: string
          enum:
            - regex
        regex:
          type: string
        caseSensitive:
          type: boolean
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````