Skip to main content

DIAL OpenAPI to MCP configuration

The OpenAPI to MCP bridge is configured in three places: its environment variables, the application type registered in DIAL Core, and the properties of each application. This page covers registration, properties, credentials, security, and a Helm example. It is for platform engineers who deploy the bridge and assumes you know Application type schemas. Everything here is checked against bridge 0.2.1 and DIAL Core 0.49.4.

Where each setting lives​

PlaceWhat it setsReference
Environment variables of the bridgePort, log level, cache, header lists, the DIAL Core URL, and telemetryEnvironment variables
Application type in DIAL CoreThe bridge's MCP and schema endpoints, how properties are delivered, and the per-request keyRegister the application type
Properties of each applicationThe API's document, base URL, extra headers, and external serviceApplication properties
External services of an applicationThe credentials that the bridge adds to API callsCredentials from external services
DIAL Core static settingsThe headers Core strips before they reach the bridgeSecure the bridge

Register the application type​

  1. Deploy the bridge. See the Helm example. In the steps below, <BRIDGE_URL> is its URL inside your network, such as http://openapi-to-mcp:8080.

  2. Register the type in DIAL Core. Add it to applicationTypeSchemas in the DIAL Core configuration:

    {
    "applicationTypeSchemas": [
    {
    "$schema": "https://dial.epam.com/application_type_schemas/schema#",
    "$id": "https://dial.example.com/custom_application_schemas/openapi-to-mcp",
    "dial:applicationTypeDisplayName": "OpenAPI to MCP",
    "dial:applicationTypeSchemaEndpoint": "<BRIDGE_URL>/v1/configuration-support/application-schema",
    "dial:applicationTypeMcp": {
    "dial:endpoint": "<BRIDGE_URL>/mcp",
    "dial:mcpConfigDelivery": "META",
    "dial:forwardPerRequestKey": true
    }
    }
    ]
    }

    To register it in DIAL Admin instead, create an Application Runner with an ID such as the $id above. In Source type, select only MCP Endpoint. Set Endpoint to <BRIDGE_URL>/mcp and Configuration delivery to Meta, and keep Forward per request key on. Then set the runner's Schema endpoint in its Properties.

  3. Check the result. The bridge answers GET <BRIDGE_URL>/ready with {"status": "ready"}, and GET /v1/application_type_schemas/schemas on DIAL Core lists the type.

PropertyWhat it does for the bridge
$idThe type's ID. Applications refer to it as applicationTypeSchemaId.
dial:applicationTypeDisplayNameThe type's name. It overrides the name in the bridge's schema, which is also OpenAPI to MCP.
dial:applicationTypeSchemaEndpointCore downloads the bridge's schema from it, with a 5-second timeout. Core then sets the registration's own fields over the downloaded schema, so the application properties come from the bridge.
dial:endpointThe bridge's MCP endpoint. Only Streamable HTTP is supported.
dial:mcpConfigDeliveryMust be META, the default. The bridge reads the properties only from params._meta.ai_dial_config. It ignores the X-DIAL-APPLICATION-PROPERTIES header that HEADER uses.
dial:forwardPerRequestKeytrue by default. The bridge needs the key to read external-service credentials. In 0.2.1, the key also reaches the API; see Secure the bridge.

Application properties​

The bridge's schema declares four properties. All are server properties: DIAL Core doesn't return them to clients.

PropertyTitle in the schemaRequiredDescription
openapiOpenAPI SpecYesThe API's OpenAPI 3.x document, as a JSON object
base_urlBase URLNoThe API's base URL. A value without a scheme gets https://.
extra_headersExtra HeadersNoHeaders added to every API call, as an array of {"name": ..., "value": ...} objects. Each name must pass the header lists.
external_serviceExternal ServiceNoThe ID of an external service defined on the same application. The caller's credential for it is added to every API call.

The bridge also accepts these values from MCP clients that call it directly. For each value, it takes the first source that has one:

ValueSources, in order
DocumentThe X-META header; _meta.ai_dial_config.openapi; _meta.openapi
Base URLThe X-BASE-URL header; _meta.ai_dial_config.base_url; _meta.base_url; the document's first servers URL; a top-level x-base-url in the document
Extra headersThe X-EXTRA-HEADERS header, as a JSON array; _meta.ai_dial_config.extra_headers; _meta.extra_headers
External service_meta.ai_dial_config.external_service

The base URL fields also accept the spellings baseurl and baseURL. A document in a header or in _meta.openapi can be JSON or YAML text.

Credentials from external services​

When an application sets external_service, the bridge gets a credential for every tool call. Credentials aren't cached.

  1. It reads the application at GET <DIAL_URL>/v1/<application>. The application ID comes from X-DIAL-APPLICATION-ID and the key from API-KEY. It checks that the application's external_services contain the service.
  2. It asks POST <DIAL_URL>/v1/ops/external-service/credentials for the credential of the scope <application>/external_services/<service>.
  3. It adds the returned header to the API call. Each call to DIAL Core has a 10-second timeout.

A lookup that fails ends the tool call with an error result, and the API isn't called. The result's _meta["dial.epam.com/error"] holds status_code and external_service:

status_codeCause
404The application has no external service with this ID.
401DIAL Core has no credential for the user yet. _meta["dial.epam.com/auth-challenge"] holds a one-item list: [{"method": "external-service/signin", "scope": "<application>/external_services/<service>"}].
500Any other failure: DIAL_URL unset, X-DIAL-APPLICATION-ID or API-KEY missing, an error from DIAL Core, or a credential header the block list contains

When DIAL Core returns a malformed credential, or one in a header the block list contains, external_service is unknown.

A Quick App handles the 401 result: it asks the user to sign in to the service and retries the call once. This needs the client channel that DIAL Chat opens, as for MCP Toolsets.

Warning

In 0.2.1, an OAuth external service fails with 500 and "DIAL core returned a prohibited credential header". DIAL Core returns OAuth credentials in Authorization, which the default block list contains. To use one, set OUTBOUND_HEADER_BLOCKLIST to the default list without authorization. Also set OUTBOUND_HEADER_ALLOWLIST without authorization, so that extra_headers still can't set it. The development branch drops this check after 0.2.1.

Secure the bridge​

  • No client authentication. The bridge accepts every request on /mcp. Let only DIAL Core and other trusted clients reach it, for example with a network policy.
  • No destination limits. The bridge calls whatever base URL a request names, and never follows redirects. Limit its egress with network policy when your environment needs it.
  • Headers that override properties. DIAL Core passes most of a caller's headers on to the bridge. The bridge prefers X-META, X-BASE-URL, and X-EXTRA-HEADERS to the application's properties. Add all three to Core's proxy.additionalHopByHopHeaders so that Core strips them.
  • Set base_url on every application. Core writes the application's properties into _meta.ai_dial_config but keeps other fields the caller put in _meta. When an application has no base_url, a caller's _meta.ai_dial_config.base_url or _meta.base_url decides the destination. When it has no extra_headers, a caller's extra_headers are added to API calls, within the header lists.

Warning

In 0.2.1, every API call also carries the headers of the MCP request that reached the bridge. Behind DIAL Core, these include the per-request key in API-KEY and the X-DIAL-APPLICATION-ID header. FastMCP 3.4.5, which 0.2.1 locks, copies them into each call. The bridge removes only X-META, X-BASE-URL, and X-EXTRA-HEADERS, and the header lists don't apply. Use the bridge only with APIs you trust with the per-request key. Alternatively, set dial:forwardPerRequestKey to false on a type whose applications don't use external_service. The development branch removes API-KEY and X-DIAL-APPLICATION-ID after 0.2.1.

FastMCP doesn't copy host, content-length, content-type, connection, transfer-encoding, upgrade, te, keep-alive, expect, accept, authorization, proxy-authenticate, proxy-authorization, proxy-connection, or mcp-session-id.

Example: Helm values​

The bridge isn't part of the dial chart. Deploy it with the dial-extension chart 3.1.1:

image:
registry: ghcr.io
repository: epam/ai-dial-openapi-to-mcp
tag: 0.2.1
containerPorts:
http: 8080
env:
DIAL_URL: http://dial-core.dial.svc.cluster.local
livenessProbe:
enabled: true
readinessProbe:
enabled: true
httpGet:
path: /ready
port: http
helm install openapi-to-mcp dial/dial-extension --version 3.1.1 -f values.yaml --namespace dial

The chart's probes call /health unless set otherwise, so the example points readiness at /ready. The chart's Service listens on port 80 by default (service.ports.http). Use the Service's URL as <BRIDGE_URL> in the registration. DIAL_URL is needed only by applications that set external_service.

Troubleshooting​

SymptomWhat to check
Listing tools fails with "Failed to create MCP from OpenAPI spec — check server logs for details"The bridge's log. Common causes are a Swagger 2.0 or non-3.x document, a document FastMCP can't build tools from, and an extra_headers name that the header lists reject. Check the document with openapi_verify.
An application lists only openapi_verify and openapi_convertThe bridge received no document. Check that dial:mcpConfigDelivery is META and that the application's openapi isn't empty.
Core rejects MCP calls with "Application doesn't support MCP protocol"The registration has no dial:applicationTypeMcp, or the application doesn't use the type.
Core logs "Failed to download application schema"That Core can reach <BRIDGE_URL>/v1/configuration-support/application-schema within 5 seconds
A tool call returns "Tool '...' not found"The tool names the document produces. The result lists up to five of them.
"External service '...' not found in application ... external_services registry"The external_service value and the IDs of the application's external services. This is the 404 result.
"Sign-in required for external service '...'"The user hasn't signed in to the service yet. This is the 401 result.
"... DIAL_URL env var is not set" or "... no Api-Key header found"DIAL_URL on the bridge, and dial:forwardPerRequestKey on the type
"DIAL core returned a prohibited credential header"The credential's header is in OUTBOUND_HEADER_BLOCKLIST. For OAuth, see the warning in Credentials from external services.
GET /ready returns 503The bridge hasn't finished starting.