Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions docs/tools/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ agents:

## Properties

The `api` toolset accepts the following toolset-level fields in addition to the `api_config` block:

| Property | Type | Required | Description |
| ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api_config` | object | ✓ | The HTTP tool definition. See the table below. |
| `timeout` | int | ✗ | HTTP client timeout in seconds (default: `30`). Applies to every call the generated tool makes. |
| `allow_private_ips` | boolean | ✗ | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast and the unspecified address). Set to `true` only when the configured endpoint legitimately targets internal services. See [Reaching internal services](#reaching-internal-services). |

### `api_config`

| Property | Type | Required | Description |
| --------------- | ------ | -------- | ------------------------------------------------ |
| `name` | string | ✓ | Tool name (how the agent references it) |
Expand All @@ -56,8 +66,8 @@ agents:
| `instruction` | string | ✗ | Description shown to the agent |
| `args` | object | ✗ | Parameter definitions (JSON Schema properties) |
| `required` | array | ✗ | List of required parameter names |
| `headers` | object | ✗ | HTTP headers to include |
| `output_schema` | object | ✗ | JSON Schema for the response (for documentation) |
| `headers` | object | ✗ | HTTP headers to include. Values support `${env.VAR}` and `${headers.NAME}` placeholders (the latter forwards a header from the caller's incoming request, useful when docker agent is itself exposed as an HTTP server). |
| `output_schema` | object | ✗ | JSON Schema for the response. Used by MCP / Code Mode consumers; tool responses are still returned to the model as raw strings. |

## HTTP Methods

Expand Down Expand Up @@ -120,7 +130,7 @@ Use `${param}` syntax to insert parameter values into URLs:
endpoint: "https://api.example.com/users/${user_id}/posts/${post_id}"
```

Parameter values are URL-encoded automatically.
Parameter values are inserted as strings by the template expansion. Add URL encoding in the template when needed (for example, `${encodeURIComponent(city)}`).

## Headers

Expand Down Expand Up @@ -209,9 +219,30 @@ agents:

- Only supports GET and POST methods
- Response body is limited to 1MB
- 30 second timeout per request
- Default 30-second timeout per request (override with the `timeout` field)
- Only HTTP and HTTPS URLs are supported
- No support for file uploads or multipart forms
- By default, requests to non-public IP ranges (loopback, RFC1918, link-local, the cloud-metadata endpoint, multicast, the unspecified address) are refused at dial time — even when DNS for an otherwise-public host resolves there. Set `allow_private_ips: true` to disable that check.

## Reaching internal services

```yaml
toolsets:
- type: api
timeout: 60
allow_private_ips: true
api_config:
name: get_local_status
method: GET
endpoint: "http://localhost:8080/health"
instruction: Check the local service health
```

<div class="callout callout-warning" markdown="1">
<div class="callout-title">SSRF
</div>
<p>Setting <code>allow_private_ips: true</code> re-exposes the SSRF surface for this tool. Only enable it when the configured <code>endpoint</code> is a trusted internal service — a prompt-injected agent cannot redirect the call elsewhere because the endpoint is fixed in config, but redirects from the configured host can still reach unexpected places.</p>
</div>

<div class="callout callout-tip" markdown="1">
<div class="callout-title">For Complex APIs
Expand Down
23 changes: 22 additions & 1 deletion docs/tools/fetch/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The fetch tool lets agents retrieve content from one or more HTTP/HTTPS URLs. It
<div class="callout callout-info" markdown="1">
<div class="callout-title">GET only
</div>
<p>The fetch tool does <strong>not</strong> support <code>POST</code>, <code>PUT</code>, <code>DELETE</code> or other methods, and does not expose request bodies or custom headers. To call REST endpoints with other verbs, use the <a href="{{ '/tools/api/' | relative_url }}">API tool</a> or an <a href="{{ '/tools/openapi/' | relative_url }}">OpenAPI toolset</a>.</p>
<p>The fetch tool does <strong>not</strong> support <code>POST</code>, <code>PUT</code>, <code>DELETE</code> or other methods, and does not expose request bodies or per-call custom headers (the toolset can still attach static <a href="#custom-headers">credential headers</a> to every request). To call REST endpoints with other verbs, use the <a href="{{ '/tools/api/' | relative_url }}">API tool</a> or an <a href="{{ '/tools/openapi/' | relative_url }}">OpenAPI toolset</a>.</p>

</div>

Expand All @@ -34,6 +34,7 @@ toolsets:
| `allowed_domains` | array[string] | _none_ | Allow-list of hosts the tool may fetch. When set, every URL whose host is **not** in the list is rejected before any network call is made. Mutually exclusive with `blocked_domains`. |
| `blocked_domains` | array[string] | _none_ | Deny-list of hosts the tool must not fetch. URLs whose host matches one of these patterns are rejected before any network call (including `robots.txt`) is made. Mutually exclusive with `allowed_domains`. |
| `allow_private_ips` | boolean | `false` | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast, and the unspecified address). Required to reach `localhost` / internal services. See [SSRF protection](#ssrf-protection-and-reaching-localhost) below. |
| `headers` | map[string]string | _none_ | Static HTTP headers attached to **every** request the toolset issues (including `robots.txt`). Values support `${env.VAR}` for secrets. Caller-supplied entries override the default `User-Agent` and the format-driven `Accept` header. Headers are stripped on cross-host redirects so credentials never leak to a third-party host. See [Custom headers](#custom-headers) below. |

### Domain matching

Expand Down Expand Up @@ -64,6 +65,26 @@ toolsets:
timeout: 60
```

### Custom headers

Attach static headers — typically credentials — to every request. Values support `${env.VAR}` interpolation so secrets stay out of YAML, and headers are dropped on cross-host redirects so a redirect chain cannot leak them to a third-party host:

```yaml
toolsets:
- type: fetch
allowed_domains:
- docs.internal.example.com
headers:
Authorization: "Bearer ${env.INTERNAL_DOCS_TOKEN}"
X-Internal-Client: "docker-agent"
```

<div class="callout callout-warning" markdown="1">
<div class="callout-title">Pair credential headers with an allow-list
</div>
<p>When <code>headers</code> carries credentials (e.g. <code>Authorization</code>), set <code>allowed_domains</code> to the specific hosts that should receive them. Stdlib already strips a small allow-list (<code>Authorization</code>, <code>Cookie</code>, <code>WWW-Authenticate</code>) on cross-domain redirects, and the fetch tool additionally strips every operator-supplied header on cross-host redirects — but an allow-list is the strongest guarantee against accidental exfiltration.</p>
</div>

### Restrict to specific domains

```yaml
Expand Down
32 changes: 28 additions & 4 deletions docs/tools/openapi/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,36 @@ toolsets:
X-Custom-Header: "my-value"
```

### Custom timeout

Override the default 30-second HTTP timeout (applies both to fetching the spec and to the generated tool calls):

```yaml
toolsets:
- type: openapi
url: "https://api.example.com/openapi.json"
timeout: 60
```

### Reaching internal services

By default the OpenAPI tool refuses connections to non-public IP addresses, blocking SSRF attempts even when DNS resolves an otherwise-public host to an internal range. Opt in with `allow_private_ips` when the spec or its `servers` entries legitimately target localhost or your internal network:

```yaml
toolsets:
- type: openapi
url: "http://localhost:8080/openapi.json"
allow_private_ips: true
```

## Properties

| Property | Type | Required | Description |
| --------- | ----------------- | -------- | --------------------------------------------------------------------------- |
| `url` | string | ✓ | URL of the OpenAPI specification (JSON format) |
| `headers` | map[string]string | | Custom HTTP headers sent with every request. Values support `${env.VAR}` and `${headers.NAME}` placeholders. |
| Property | Type | Required | Description |
| ------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url` | string | ✓ | URL of the OpenAPI specification (JSON format). Supports `${env.VAR}` interpolation. |
| `headers` | map[string]string | ✗ | Custom HTTP headers sent with every request — both the spec fetch and every generated tool call. Values support `${env.VAR}` and `${headers.NAME}` placeholders (the latter forwards a header from the caller's incoming request when docker agent is exposed as a server). |
| `timeout` | int | ✗ | HTTP client timeout in seconds (default: `30`). Applies to both the spec fetch and the generated tools' requests. |
| `allow_private_ips` | boolean | ✗ | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast and the unspecified address). Set to `true` only when the spec or its servers legitimately target internal services. By default such addresses are refused at dial time, after DNS resolution, so DNS rebinding cannot bypass the check. |

## How it works

Expand Down
Loading