Documentsdify
Custom Tool OpenAPI Integration
Custom Tool OpenAPI Integration
Type
Topic
Status
Published
Created
Jul 19, 2026
Updated
Jul 19, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Custom Tool OpenAPI Integration#

Overview#

Dify's custom tool system (ApiTool) allows users to register arbitrary HTTP APIs by supplying an OpenAPI (or Swagger) schema. At parse time, the schema is converted into one or more ApiToolBundle objects — one per operation — each carrying a frozen server_url, HTTP method, operation parameters, and the raw OpenAPI operation dict. These bundles drive every subsequent invocation.


Schema Parsing and Server URL Extraction#

Entry point: ApiBasedToolSchemaParser.parse_openapi_to_tool_bundle()

The parser accepts an OpenAPI dict (JSON or YAML), Swagger 2.x, or an OpenAI plugin JSON manifest. For Swagger, parse_swagger_to_openapi() upgrades it to OpenAPI 3.0 before the main parse path runs . Auto-detection order is OpenAPI → Swagger → OpenAI plugin .

Server URL selection :

  1. The parser takes servers[0]["url"] as the default.
  2. If an HTTP request context exists and the X-Request-Env header is set, it scans the servers array for the first entry whose "env" field matches and uses that URL instead.
  3. No other server selection logic exists.

Bundle construction: For each path+method combination, the parser concatenates the resolved server_url with the path string and stores the result as ApiToolBundle.server_url . This string is baked in at parse time — it is not re-evaluated on each call.


Invocation Flow#

At invocation, ApiTool._invoke() calls:

  1. assembling_request() — builds auth headers and validates required parameters.
  2. do_http_request() — resolves in: path tokens via string replace (e.g. {id} → value), merges in: query / in: header / in: cookie parameters, serialises the request body, then dispatches via ssrf_proxy.

The URL passed to do_http_request is always self.api_bundle.server_url — the value frozen during parsing .


Limitations on Dynamic Parameterization#

LimitationDetail
No runtime server URL overrideThe server_url on ApiToolBundle is a plain str field set once at parse time . There is no mechanism to substitute it per-invocation.
OpenAPI variables not supportedThe OpenAPI 3.x servers[].variables templating (e.g. https://{tenant}.example.com) is silently ignored; the raw URL string is used verbatim .
Only one server effectively usedThe X-Request-Env fallback notwithstanding, all possible server URLs must be pre-defined in the schema — nothing can be injected at call time.
Path parameters onlyOnly path-level {param} tokens (OpenAPI in: path) are interpolated at runtime . The host portion of the URL is never touched.

Workarounds#

  • Multiple servers entries with env tags: Pre-define all base URLs in the schema; use the X-Request-Env header to select among them .
  • Reverse proxy with stable address: Place a proxy in front of your backend so the custom tool always hits a fixed URL.
  • Code node in a workflow: For fully dynamic base URLs, use a Code node to issue the HTTP request directly instead of a custom tool.

Key Files#

FileRole
api/core/tools/utils/parser.pySchema parsing; server URL extraction; bundle construction
api/core/tools/entities/tool_bundle.pyApiToolBundle data model
api/core/tools/custom_tool/tool.pyApiTool invocation, auth assembly, HTTP dispatch