Connect agents to OpenAPI tools

Connect your Microsoft Foundry agents to external APIs using OpenAPI 3.0 and 3.1 specifications. The Foundry model powering your agent can call external services, retrieve real-time data, and extend its capabilities beyond built-in functions.

OpenAPI specifications define a standard way to describe HTTP APIs, so you can integrate existing services with your agents. Use anonymous, API key, or project managed identity authentication. For help choosing an authentication method, see Choose an authentication method.

Tip

Consider adding this tool using a toolbox. By using a toolbox, you are able to reuse the tool across agents and runtimes, as well as centralizing credential management, versioning, and policy enforcement through a managed MCP endpoint. See the toolbox quickstart.

Prerequisites

Before you begin, make sure you have:

  • An Azure subscription with the right permissions.

  • Foundry User role on the Foundry project to create and run agents.

    Important

    The Foundry RBAC roles were recently renamed. Foundry User, Foundry Owner, Foundry Account Owner, and Foundry Project Manager were previously named Azure AI User, Azure AI Owner, Azure AI Account Owner, and Azure AI Project Manager. You might still see the previous names in some places while the rename rolls out. The role IDs and core permissions are unchanged by the rename.

  • Foundry Project Manager role on the Foundry project to create a project connection. This role includes anonymous, API key, and project managed identity connections.

  • A Foundry project created with an endpoint configured.

  • An AI model deployed in your project. Confirm that both the model and project region support OpenAPI tools in Tool support by region and model.

  • A basic or standard agent environment.

  • Dependencies installed for your preferred language:

    • Python SDK examples: azure-ai-projects, azure-identity, and jsonref. The direct Responses example also uses openai.
    • C# SDK examples: Azure.AI.Projects, Azure.AI.Projects.Agents, Azure.AI.Extensions.OpenAI, and Azure.Identity. The direct HTTP example uses Azure.Identity.
    • JavaScript/TypeScript SDK examples: @azure/ai-projects and @azure/identity. The direct HTTP example uses @azure/identity.
    • Java HTTP example: com.azure:azure-identity and com.fasterxml.jackson.core:jackson-databind.
  • OpenAPI 3.0 or 3.1 specification file that meets these requirements:

    • Each function must have an operationId (required for the OpenAPI tool).
    • operationId should only contain letters, -, and _.
    • Use descriptive names to help models efficiently decide which function to use.
    • Supported request body content types: application/json, application/json-patch+json
  • For project managed identity authentication: an OpenAPI project connection with authType: "ProjectManagedIdentity" and the least-privileged target-service role assigned to the project's managed identity. Pass the connection's full resource ID to the tool. See Create a project managed identity connection.

  • For API key/token authentication: a project connection configured with your API key or token. See Add a new connection to your project.

  • For anonymous authentication: an OpenAPI project connection with authType: "None". See Create an anonymous OpenAPI connection.

Environment variables

Variable Description
FOUNDRY_PROJECT_ENDPOINT Your Foundry project endpoint, such as https://<account>.services.ai.azure.com/api/projects/<project>. Don't use the external API endpoint.
FOUNDRY_MODEL_DEPLOYMENT_NAME Your deployed model name.
OPENAPI_CONNECTION_ID The full ARM resource ID of the OpenAPI connection for the selected authentication method.
TOOLBOX_CONNECTION_ID For samples that attach a toolbox through a project connection, the full resource ID of that separate connection to the toolbox MCP endpoint.

Note

The FOUNDRY_PROJECT_ENDPOINT value refers to your Microsoft Foundry project endpoint, not the external OpenAPI service endpoint. You can find this endpoint in the Microsoft Foundry portal under your project’s Overview page. This endpoint is required to authenticate the agent service and is separate from any OpenAPI endpoints defined in your specification file.

Usage support

The following table shows SDK and setup support.

Microsoft Foundry support Python SDK C# SDK JavaScript SDK Java SDK REST API Basic agent setup Standard agent setup
✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️

Note

The Java example in this article uses Java's HTTP client and Azure Identity to send the same Responses payload as the other languages. It doesn't require typed OpenAPI tool models.

Run the anonymous first-success flow

Start with the anonymous weather API to verify that your agent can load an OpenAPI specification and call an operation. Create an OpenAPI project connection even for anonymous authentication, and pass its full resource ID to the tool. Anonymous authentication doesn't require an external API credential. See Create an anonymous OpenAPI connection.

  1. Install the SDK package for your selected language from Prerequisites.
  2. Download weather_openapi.json, and save it to the assets path used by the sample.
  3. Set your Foundry project endpoint and model deployment values.
  4. Create an anonymous OpenAPI connection for https://wttr.in, and set OPENAPI_CONNECTION_ID to its full resource ID.
  5. Run the anonymous sample in your selected language section.
  6. Confirm that the response contains current weather for Seattle, and then delete the agent version created by the sample.

After the anonymous call succeeds, configure the authentication required by your target API. Keep API key authentication, bearer-token authentication, and project managed identity authentication as separate variants.

Understand limitations

  • Your OpenAPI spec must include operationId for each operation, and operationId can include only letters, -, and _.
  • Supported request body content types: application/json, application/json-patch+json.
  • For API key authentication, use one API key security scheme per OpenAPI tool. If you need multiple security schemes, create multiple OpenAPI tools.
  • Rotate API keys and bearer tokens regularly and immediately after suspected exposure. Update the project connection when credentials change; don't place credentials in the OpenAPI specification or source code.

Configure OpenAPI authentication in the Foundry portal

When you add an OpenAPI tool through Tools > Custom > OpenAPI, create a project connection for the tool. Anonymous, API key, and Managed identity authentication all require a connection, whether you configure the tool through the portal, SDK, or REST API.

The portal's Managed identity option uses the Foundry project's managed identity, not the Foundry account's managed identity. OpenAPI tools in toolboxes have always required project managed identity, regardless of subscription history. Account managed identity is supported only for OpenAPI tools attached directly to prompt agents in existing subscriptions. Migrate those configurations to project managed identity as soon as possible. See Managed identity support.

Anonymous authentication means the target API doesn't require credentials. It doesn't mean you can skip creating the connection.

Authentication Connection configuration
Anonymous Create an OpenAPI project connection with no authentication (authType: "None"). No API key or token is required.
API key Create a project connection that stores the API key. Match the key name to the header or query parameter in the OpenAPI security scheme. See Authenticate with API key.
Managed identity (project managed identity) Create an OpenAPI project connection with authType: "ProjectManagedIdentity", the target API endpoint, and the audience expected by that API. Assign the project's managed identity the required role on the target service. This option doesn't use the account's managed identity.

Configure anonymous authentication

  1. Open Tools > Custom > OpenAPI in your Foundry project.
  2. In Create an OpenAPI tool, enter the tool's Name and Description.
  3. Set Authentication method to Anonymous.
  4. Under Connection, select an existing anonymous connection or select Create a new connection to create one.
  5. Enter the OpenAPI 3.0+ schema, and select Create tool.

The Connection field is required even when Anonymous is selected.

Screenshot of anonymous OpenAPI authentication with a required Connection field and a Create a new connection button.

Configure managed identity authentication

The Managed identity option requires the project's managed identity. An existing role assignment for the account's managed identity doesn't grant access to the project's managed identity.

  1. In Create an OpenAPI tool, set Authentication method to Managed identity.
  2. Under Connection, select an existing project managed identity connection or select Create a new connection.
  3. In Create OpenAPI connection, enter a Connection name, and set Authentication type to Managed identity.
  4. Enter the Target URL for the API and the Audience that the API expects. The audience isn't your Foundry project endpoint.
  5. Select Create connection, and select that connection in the tool's Connection field.
  6. Enter the tool's Name, Description, and OpenAPI 3.0+ schema, and select Create tool.

Assign the project's managed identity the required role on the target service before calling the tool.

Screenshot of the Create OpenAPI connection dialog showing required Connection name, Authentication type, Target URL, and Audience fields for managed identity.

For project managed identity connection setup through REST, see Create a project managed identity connection. When you use that connection in code, pass its full resource ID with auth.type: "project_connection".

The SDK and REST examples also reference a project connection. Create the connection before running them.

Create an anonymous OpenAPI connection

Use the portal steps in the preceding section, or run the following Bash commands with Azure CLI and curl after signing in with az login. Replace the placeholders with your Foundry project details. This connection uses authType: "None" because the weather API doesn't require credentials.

SUB="<subscription-id>"
RESOURCE_GROUP="<resource-group>"
ACCOUNT="<foundry-account-name>"
PROJECT_NAME="<foundry-project-name>"
PROJECT="/subscriptions/$SUB/resourceGroups/$RESOURCE_GROUP"
PROJECT="$PROJECT/providers/Microsoft.CognitiveServices"
PROJECT="$PROJECT/accounts/$ACCOUNT/projects/$PROJECT_NAME"
export OPENAPI_CONNECTION_ID="$PROJECT/connections/weather-anonymous"

ARM_TOKEN="$(az account get-access-token \
  --subscription "$SUB" \
  --resource https://management.azure.com \
  --query accessToken -o tsv)"

curl --fail-with-body --request PUT \
  --url "https://management.azure.com$OPENAPI_CONNECTION_ID?api-version=2025-06-01" \
  --header "Authorization: Bearer $ARM_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "properties": {
      "category": "OpenAPI",
      "authType": "None",
      "target": "https://wttr.in",
      "metadata": {
        "type": "openapi"
      }
    }
  }'

Reference: Foundry project connection resource schema.

Pass OPENAPI_CONNECTION_ID in the tool's auth.security_scheme.project_connection_id, with auth.type: "project_connection". The connection's authType determines that the target API is called anonymously.

Add OpenAPI tools to a toolbox

Use this pattern to expose a REST API described by an OpenAPI specification. For anonymous, API key, or project managed identity authentication, set the tool's auth.type to project_connection. The connection's authType determines how Foundry authenticates to the target API.

For managed identity authentication, toolboxes require project managed identity. Account managed identity isn't supported in toolboxes, including for existing subscriptions.

The following snippets show tool configuration, not complete programs. Replace each empty spec object with your OpenAPI specification. For toolbox creation, use the complete language samples in the following sections.

Important

When you use managed identity authentication, assign the Foundry project's managed identity the least-privileged RBAC role that permits the required API operations on the target service. For example, assign Reader on the target Azure resource only when the API needs read-only Azure Resource Manager access. Without the required assignment, the agent receives a 401 Unauthorized response when calling the API. For full setup steps, see Authenticate by using managed identity.

Anonymous auth:

Create an OpenAPI connection with authType: "None" first, and replace <OPENAPI_CONNECTION_ID> with its full resource ID.

{
  "description": "REST API via OpenAPI spec",
  "tools": [
    {
      "type": "openapi",
      "openapi": {
        "name": "my-api",
        "spec": {},
        "auth": {
          "type": "project_connection",
          "security_scheme": {
            "project_connection_id": "<OPENAPI_CONNECTION_ID>"
          }
        }
      }
    }
  ]
}

Project connection auth:

Use this pattern when the API requires a key or token stored in a Foundry project connection.

{
  "description": "REST API with connection-based auth",
  "tools": [
    {
      "type": "openapi",
      "openapi": {
        "name": "my-api",
        "spec": {},
        "auth": {
          "type": "project_connection",
          "security_scheme": {
            "project_connection_id": "<OPENAPI_CONNECTION_ID>"
          }
        }
      }
    }
  ]
}

Project managed identity auth:

Create an OpenAPI project connection with authType: "ProjectManagedIdentity", and pass its full resource ID with auth.type: "project_connection". Don't use the direct managed_identity audience configuration in a toolbox.

{
  "description": "REST API with project managed identity auth",
  "tools": [
    {
      "type": "openapi",
      "openapi": {
        "name": "my-api",
        "spec": {},
        "auth": {
          "type": "project_connection",
          "security_scheme": {
            "project_connection_id": "<OPENAPI_CONNECTION_ID>"
          }
        }
      }
    }
  ]
}
import os
from azure.ai.projects.models import (
    OpenApiFunctionDefinition,
    OpenApiProjectConnectionAuthDetails,
    OpenApiProjectConnectionSecurityScheme,
    OpenApiToolboxTool,
)

tools = [
    OpenApiToolboxTool(
        openapi=OpenApiFunctionDefinition(
            name="my-api",
            spec={},
            auth=OpenApiProjectConnectionAuthDetails(
                security_scheme=OpenApiProjectConnectionSecurityScheme(
                    project_connection_id=os.environ["OPENAPI_CONNECTION_ID"]
                )
            ),
        )
    )
]
using System;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects.Agents;

BinaryData specBytes = BinaryData.FromString("<OpenAPI spec JSON>");
OpenApiToolboxTool tool = new(
    new OpenApiFunctionDefinition(
        name: "my-api",
        specification: specBytes,
        authentication: new OpenApiProjectConnectionAuthenticationDetails(
            new OpenApiProjectConnectionSecurityScheme(
                Environment.GetEnvironmentVariable("OPENAPI_CONNECTION_ID")
                ?? throw new InvalidOperationException(
                    "Set OPENAPI_CONNECTION_ID before running.")))
    )
);

ToolboxVersion toolboxVersion = await toolboxClient.CreateVersionAsync(
    name: "my-toolbox",
    tools: [tool],
    description: "REST API via OpenAPI spec"
);
const connectionId = process.env.OPENAPI_CONNECTION_ID;
if (!connectionId) {
  throw new Error("Set OPENAPI_CONNECTION_ID before running.");
}

const tools = [
  {
    type: "openapi",
    openapi: {
      name: "my-api",
      spec: { /* paste OpenAPI spec object here */ },
      auth: {
        type: "project_connection",
        security_scheme: {
          project_connection_id: connectionId,
        },
      },
    },
  },
];

Create an OpenAPI toolbox with the Azure Developer CLI

OpenAPI tools embed the spec directly under tools:. Connection-based auth (connection_auth) references a project connection. Create a connection for anonymous authentication too.

Step 1. Create the auth connection

For anonymous authentication, follow Create an anonymous OpenAPI connection. For API key authentication, use the following command:

# API-key auth (passed by the platform on every call)
# Set OPENAPI_AUTHORIZATION_HEADER in your shell without committing its value.
azd ai connection create my-api-conn \
  --kind remote-tool \
  --target https://api.example.com \
  --auth-type custom-keys \
  --custom-key "Authorization=$OPENAPI_AUTHORIZATION_HEADER"

For the full set of azd ai connection create flags, see Toolbox MCP authentication and configuration.

Step 2. Define the toolbox

The OpenAPI spec is inline under tools[].openapi.spec.

# my-toolbox.yaml
description: OpenAPI toolbox
tools:
  - type: openapi
    name: my-api
    openapi:
      name: my-api
      spec:
        openapi: "3.0.1"
        info:
          title: "My API"
          version: "1.0"
        servers:
          - url: https://api.example.com/v1
        paths:
          /search:
            get:
              operationId: search
              parameters:
                - name: query
                  in: query
                  required: true
                  schema:
                    type: string
              responses:
                "200":
                  description: OK
      auth:
        type: connection_auth
        connection_id: my-api-conn

For anonymous APIs, keep connection-based authentication. For example, to use the weather connection created earlier, replace the example specification with weather_openapi.json and use this auth: block:

      auth:
        type: connection_auth
        connection_id: weather-anonymous

Step 3. Create the toolbox

azd ai toolbox create my-toolbox --from-file my-toolbox.yaml

Before you run the code samples

  • Create the OpenAPI project connection before running any sample, including anonymous examples. For the weather samples, use an anonymous connection targeting https://wttr.in, and set OPENAPI_CONNECTION_ID to its full ARM resource ID.
  • Download the maintained tripadvisor_openapi.json specification and save it to the assets path used by your language sample.

Note

  • You need the latest SDK package. The .NET SDK is currently in preview. See the quickstart for details.
  • Use the full connection resource ID: /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<account>/projects/<project>/connections/<connection>.

Important

For API key authentication to work, your OpenAPI specification file must include:

  1. A securitySchemes section with your API key configuration, such as the header name and parameter name.
  2. A security section that references the security scheme.
  3. A project connection configured with the matching key name and value.

Without these configurations, the API key isn't included in requests. For detailed setup instructions, see the Authenticate with API key section.

You can also use token-based authentication (for example, a Bearer token) by storing the token in a project connection. For Bearer token auth, create a Custom keys connection with key set to Authorization and value set to Bearer <token> (replace <token> with your actual token). The word Bearer followed by a space must be included in the value. For details, see Set up a Bearer token connection.

Sample of using Agents with OpenAPI tool

This example demonstrates how to use services described by an OpenAPI specification by using an agent. It uses the wttr.in service to get weather and its specification file weather_openapi.json. Select Prompt Agents to use the Azure AI Projects SDK to create a server-side prompt agent, or Hosted Agents to use the Microsoft Agent Framework to build an ephemeral, in-process agent.

Prompt agents

import os
import jsonref
from typing import Any, cast
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    PromptAgentDefinition,
    OpenApiTool,
    OpenApiFunctionDefinition,
    OpenApiProjectConnectionAuthDetails,
    OpenApiProjectConnectionSecurityScheme,
)

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"
AGENT_NAME = "MyAgent"

# Create a client to call Foundry API
with AIProjectClient(
    endpoint=PROJECT_ENDPOINT,
    credential=DefaultAzureCredential(),
) as project:
    weather_asset_file_path = os.path.abspath(
        os.path.join(os.path.dirname(__file__), "../assets/weather_openapi.json")
    )

    with open(weather_asset_file_path, "r") as f:
        openapi_weather = cast(dict[str, Any], jsonref.loads(f.read()))

    # Initialize agent OpenAPI tool using the read in OpenAPI spec
    weather_tool = OpenApiTool(
        openapi=OpenApiFunctionDefinition(
            name="get_weather",
            spec=openapi_weather,
            description="Retrieve weather information for a location.",
            auth=OpenApiAnonymousAuthDetails(),
        )
    )

    agent = project.agents.create_version(
        agent_name=AGENT_NAME,
        definition=PromptAgentDefinition(
            model="gpt-4.1-mini",
            instructions="You are a helpful assistant.",
            tools=[weather_tool],
        ),
    )

    with project.get_openai_client(agent_name=agent.name) as openai:
        response = openai.responses.create(
            input="What's the weather in Seattle?",
        )
        print(response.output_text)

    # Clean up resources
    project.agents.delete_version(agent_name=agent.name, agent_version=agent.version)

This example creates a prompt agent with an OpenAPI tool that calls the wttr.in weather API using anonymous authentication. The tool is attached directly to the agent definition. When you run the code:

  1. It loads the weather OpenAPI specification from a local JSON file.
  2. Creates a prompt agent with the weather tool configured for anonymous access.
  3. Sends a query asking about Seattle's weather.
  4. The agent uses the OpenAPI tool to call the weather API and returns formatted results.
  5. Cleans up by deleting the agent version.

Hosted agents

This sample uses FoundryChatClient from the Microsoft Agent Framework and connects to the toolbox MCP endpoint by using FoundryToolbox. Install compatible package versions with pip install "agent-framework-foundry==1.10.4" "azure-ai-projects>=2.3.0,<2.4.0" jsonref, set the FOUNDRY_PROJECT_ENDPOINT environment variable, and sign in with az login. OpenApiToolboxTool is the toolbox-specific model; use OpenApiTool only when attaching the tool directly to a prompt agent.

import asyncio
import os
import jsonref
from typing import Any, cast

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient, FoundryToolbox
from azure.identity import AzureCliCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    OpenApiToolboxTool,
    OpenApiFunctionDefinition,
    OpenApiProjectConnectionAuthDetails,
    OpenApiProjectConnectionSecurityScheme,
)

PROJECT_ENDPOINT = os.environ["FOUNDRY_PROJECT_ENDPOINT"]


async def main() -> None:
    credential = AzureCliCredential()

    # 1. Create the OpenAPI tool and add it to a toolbox. Using a toolbox is the
    #    recommended way to give agents tools: curate tools once and reuse the
    #    toolbox across agents. See /azure/foundry/agents/concepts/toolbox-overview
    project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=credential)

    weather_asset_file_path = os.path.abspath(
        os.path.join(os.path.dirname(__file__), "../assets/weather_openapi.json")
    )
    with open(weather_asset_file_path, encoding="utf-8") as f:
        openapi_weather = cast(dict[str, Any], jsonref.loads(f.read()))

    weather_tool = OpenApiToolboxTool(
        openapi=OpenApiFunctionDefinition(
            name="get_weather",
            spec=openapi_weather,
            description="Retrieve weather information for a location.",
            auth=OpenApiProjectConnectionAuthDetails(
                security_scheme=OpenApiProjectConnectionSecurityScheme(
                    project_connection_id=os.environ["OPENAPI_CONNECTION_ID"]
                )
            ),
        )
    )

    toolbox = project.toolboxes.create_version(
        name="openapi-toolbox",
        description="Toolbox with the OpenAPI weather tool",
        tools=[weather_tool],
    )

    # 2. The toolbox exposes an MCP-compatible endpoint.
    TOOLBOX_MCP_URL = (
        f"{PROJECT_ENDPOINT}/toolboxes/{toolbox.name}"
        f"/versions/{toolbox.version}/mcp?api-version=v1"
    )

    # 3. Attach the toolbox to the hosted agent as an MCP tool.
    toolbox_tool = FoundryToolbox(credential, url=TOOLBOX_MCP_URL)

    agent = Agent(
        client=FoundryChatClient(credential=credential),
        instructions="You are a helpful assistant. Use the OpenAPI weather tool to answer questions.",
        tools=[toolbox_tool],
    )

        result = await agent.run("What's the weather in Seattle?")
        print(f"Agent: {result.text}")


if __name__ == "__main__":
    asyncio.run(main())

Expected output

Agent: The weather in Seattle is currently cloudy with a temperature of 52°F (11°C)...

Sample of using Agents with OpenAPI tool

This example demonstrates how to use services described by an OpenAPI specification by using an agent. It uses the wttr.in service to get weather and its specification file weather_openapi.json. Select Prompt Agents to use the Azure AI Projects SDK to create a server-side prompt agent, or Hosted Agents to use the Microsoft Agent Framework to build an ephemeral, in-process agent.

Prompt agents

This example uses synchronous methods of the Azure AI Projects client library. For an example that uses asynchronous methods, see the sample in the Azure SDK for .NET repository on GitHub.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using Azure.AI.Projects;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using OpenAI.Responses;

#pragma warning disable AAIP002

class OpenAPIDemo
{
    // Utility method to get the OpenAPI specification file from the Assets folder.
    private static string GetFile([CallerFilePath] string pth = "")
    {
        var dirName = Path.GetDirectoryName(pth) ?? "";
        return Path.Combine(dirName, "Assets", "weather_openapi.json");
    }

    public static void Main()
    {
        var projectEndpoint =
            Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
            ?? throw new InvalidOperationException(
                "Set FOUNDRY_PROJECT_ENDPOINT before running.");
        var deploymentName =
            Environment.GetEnvironmentVariable("FOUNDRY_MODEL_DEPLOYMENT_NAME")
            ?? throw new InvalidOperationException(
                "Set FOUNDRY_MODEL_DEPLOYMENT_NAME before running.");

        // Create project client to call Foundry API
        AIProjectClient projectClient = new(
            endpoint: new Uri(projectEndpoint),
            tokenProvider: new DefaultAzureCredential());

        // The connection specifies anonymous authentication to the weather API.
        string filePath = GetFile();
        OpenApiFunctionDefinition toolDefinition = new(
            name: "get_weather",
            specification: BinaryData.FromBytes(File.ReadAllBytes(filePath)),
            authentication: new OpenApiProjectConnectionAuthenticationDetails(
                new OpenApiProjectConnectionSecurityScheme(
                    Environment.GetEnvironmentVariable("OPENAPI_CONNECTION_ID")
                    ?? throw new InvalidOperationException(
                        "Set OPENAPI_CONNECTION_ID before running.")))
        );
        toolDefinition.Description = "Retrieve weather information for a location.";
        OpenApiTool openapiTool = new(toolDefinition);

        // Create the agent definition and the agent version.
        DeclarativeAgentDefinition agentDefinition = new(model: deploymentName)
        {
            Instructions = "You are a helpful assistant.",
            Tools = { openapiTool }
        };
        ProjectsAgentVersion agentVersion = projectClient.AgentAdministrationClient.CreateAgentVersion(
            agentName: "myAgent",
            options: new(agentDefinition));

        // Create a response object and ask the question about the weather in Seattle, WA.
        ProjectResponsesClient responseClient = projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentVersion.Name);
        ResponseResult response = responseClient.CreateResponse(
                userInputText: "Use the OpenAPI tool to print out, what is the weather in Seattle, WA today."
            );
        Console.WriteLine(response.GetOutputText());

        // Finally, delete all the resources created in this sample.
        projectClient.AgentAdministrationClient.DeleteAgentVersion(agentName: agentVersion.Name, agentVersion: agentVersion.Version);
    }
}

What this code does

This C# example creates an agent with an OpenAPI tool that retrieves weather information from wttr.in by using anonymous authentication. When you run the code:

  1. It reads the weather OpenAPI specification from a local JSON file.
  2. Creates an agent with the weather tool configured.
  3. Sends a request asking about Seattle's weather using the OpenAPI tool.
  4. The agent calls the weather API and returns the results.
  5. Cleans up by deleting the agent.

Required inputs

  • Environment variables: FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, and OPENAPI_CONNECTION_ID.
  • Local file: Assets/weather_openapi.json (OpenAPI specification)

Expected output

The weather in Seattle, WA today is cloudy with temperatures around 52°F...

Common errors

  • FileNotFoundException: OpenAPI specification file not found in Assets folder
  • UnauthorizedAccessException: Invalid credentials or insufficient RBAC permissions
  • API key not injected: Verify your OpenAPI spec includes both securitySchemes (in components) and security sections with matching scheme names

Hosted agents

This sample creates the OpenAPI toolbox with the Azure AI Projects SDK, and then uses the Microsoft Agent Framework AddFoundryToolboxes integration. Use an ASP.NET Core project with Azure.AI.AgentServer.Responses and Microsoft.Agents.AI.Foundry.Hosting, in addition to the C# dependencies in Prerequisites. Set FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, and OPENAPI_CONNECTION_ID, and sign in with az login.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using Azure.AI.AgentServer.Responses;
using Azure.AI.Projects;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.AspNetCore.Builder;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;
using Microsoft.Extensions.DependencyInjection;
using OpenAI.Chat;

string GetFile([CallerFilePath] string pth = "")
{
    var dirName = Path.GetDirectoryName(pth) ?? "";
    return Path.Combine(dirName, "Assets", "weather_openapi.json");
}

string projectEndpoint = Environment.GetEnvironmentVariable(
    "FOUNDRY_PROJECT_ENDPOINT")
    ?? throw new InvalidOperationException("Set FOUNDRY_PROJECT_ENDPOINT.");
string deploymentName = Environment.GetEnvironmentVariable(
    "FOUNDRY_MODEL_DEPLOYMENT_NAME")
    ?? throw new InvalidOperationException("Set FOUNDRY_MODEL_DEPLOYMENT_NAME.");
DefaultAzureCredential credential = new();

// 1. Create the OpenAPI tool and add it to a toolbox. Using a toolbox is the
//    recommended way to give agents tools. See /azure/foundry/agents/concepts/toolbox-overview
AIProjectClient projectClient = new(endpoint: new Uri(projectEndpoint), tokenProvider: credential);
string filePath = GetFile();
OpenApiFunctionDefinition toolDefinition = new(
    name: "get_weather",
    specification: BinaryData.FromBytes(File.ReadAllBytes(filePath)),
    authentication: new OpenApiProjectConnectionAuthenticationDetails(
        new OpenApiProjectConnectionSecurityScheme(
            Environment.GetEnvironmentVariable("OPENAPI_CONNECTION_ID")
            ?? throw new InvalidOperationException(
                "Set OPENAPI_CONNECTION_ID before running.")))
);
toolDefinition.Description = "Retrieve weather information for a location.";
OpenApiToolboxTool openapiTool = new(toolDefinition);
ToolboxVersion toolboxVersion = projectClient.AgentAdministrationClient
    .GetAgentToolboxes().CreateVersion(
        name: "openapi-toolbox",
        tools: [openapiTool],
        description: "Toolbox with the OpenAPI weather tool");
projectClient.AgentAdministrationClient.GetAgentToolboxes()
    .UpdateDefaultVersion(toolboxVersion.Name, toolboxVersion.Version);

// Create the hosted agent and register the toolbox integration.
AIAgent agent = projectClient.AsAIAgent(
    model: deploymentName,
    instructions: "You are a helpful assistant with access to the toolbox tools.",
    name: "hosted-toolbox-agent");

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.Services.AddFoundryToolboxes(credential, toolboxVersion.Name);

var app = builder.Build();
app.MapFoundryResponses();
app.Run();

Expected output

The sample starts an HTTP server. When you send a Responses request asking about the weather, the agent calls the API through the toolbox and returns the current conditions:

The current weather in Seattle is <temperature> with <conditions>.

For the full sample including authenticated API patterns, see Agent_Step17_OpenAPITools.


Sample of using Agents with OpenAPI tool on Web service, requiring authentication

In this example, you attach an authenticated OpenAPI tool directly to a prompt agent. You use the TripAdvisor specification and an API key stored in a project connection.

The TripAdvisor service requires API key authentication. Create the project connection as described in Authenticate with API key, and set OPENAPI_CONNECTION_ID to its full resource ID. The connection's key name must match the TripAdvisor specification.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using OpenAI.Responses;

#pragma warning disable AAIP002

class OpenAPIConnectedDemo
{
    // Utility method to get the OpenAPI specification file from the Assets folder.
    private static string GetFile([CallerFilePath] string pth = "")
    {
        var dirName = Path.GetDirectoryName(pth) ?? "";
        return Path.Combine(dirName, "Assets", "tripadvisor_openapi.json");
    }

    public static void Main()
    {
        var projectEndpoint =
            Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
            ?? throw new InvalidOperationException(
                "Set FOUNDRY_PROJECT_ENDPOINT before running.");
        var deploymentName =
            Environment.GetEnvironmentVariable("FOUNDRY_MODEL_DEPLOYMENT_NAME")
            ?? throw new InvalidOperationException(
                "Set FOUNDRY_MODEL_DEPLOYMENT_NAME before running.");

        // Create project client to call Foundry API
        AIProjectClient projectClient = new(
            endpoint: new Uri(projectEndpoint),
            tokenProvider: new DefaultAzureCredential());

        // Create an OpenAPI tool with authentication by project connection security scheme.
        string filePath = GetFile();
        var connectionId =
            Environment.GetEnvironmentVariable("OPENAPI_CONNECTION_ID")
            ?? throw new InvalidOperationException(
                "Set OPENAPI_CONNECTION_ID to the TripAdvisor connection ID.");
        OpenApiFunctionDefinition toolDefinition = new(
            name: "tripadvisor",
            specification: BinaryData.FromBytes(File.ReadAllBytes(filePath)),
            authentication: new OpenApiProjectConnectionAuthenticationDetails(new OpenApiProjectConnectionSecurityScheme(
                projectConnectionId: connectionId
            ))
        );
        toolDefinition.Description = "Trip Advisor API to get travel information.";
        OpenApiTool openapiTool = new(toolDefinition);

        // Create the agent definition and the agent version.
        DeclarativeAgentDefinition agentDefinition = new(model: deploymentName)
        {
            Instructions = "You are a helpful assistant.",
            Tools = { openapiTool }
        };
        ProjectsAgentVersion agentVersion = projectClient.AgentAdministrationClient.CreateAgentVersion(
            agentName: "myAgent",
            options: new(agentDefinition));

        // Create a response object and ask the question about the hotels in France.
        // Test the Web service access before you run production scenarios.
        // It can be done by setting:
        // ToolChoice = ResponseToolChoice.CreateRequiredChoice()`
        // in the ResponseCreationOptions. This setting will
        // force Agent to use tool and will trigger the error if it is not accessible.
        ProjectResponsesClient responseClient = projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentVersion.Name);
        CreateResponseOptions responseOptions = new()
        {
            ToolChoice = ResponseToolChoice.CreateRequiredChoice(),
            InputItems =
            {
                ResponseItem.CreateUserMessageItem("Recommend me 5 top hotels in paris, France."),
            }
        };
        ResponseResult response = responseClient.CreateResponse(
            options: responseOptions
        );
        Console.WriteLine(response.GetOutputText());

        // Finally, delete all the resources we have created in this sample.
        projectClient.AgentAdministrationClient.DeleteAgentVersion(agentName: agentVersion.Name, agentVersion: agentVersion.Version);
    }
}

What this code does

This C# example uses an OpenAPI tool with API key authentication through a project connection. When you run the code:

  1. It loads the TripAdvisor OpenAPI specification from a local file.
  2. It references the TripAdvisor project connection containing your API key.
  3. It attaches the TripAdvisor tool to the agent, configured to use the connection for authentication.
  4. Sends a request for hotel recommendations in Paris.
  5. The agent calls the TripAdvisor API using your stored API key and returns results.
  6. Cleans up by deleting the agent.

Required inputs

  • Environment variables: FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, and OPENAPI_CONNECTION_ID.
  • Local file: Assets/tripadvisor_openapi.json
  • Project connection: tripadvisor with valid API key configured

Expected output

Here are 5 top hotels in Paris, France:
1. Hotel Name - Rating: 4.5/5, Location: ...
2. Hotel Name - Rating: 4.4/5, Location: ...
...

Common errors

  • ConnectionNotFoundException: No project connection named tripadvisor found.
  • AuthenticationException: Invalid API key in project connection, or missing/incorrect securitySchemes configuration in OpenAPI spec.
  • Tool not used: Verify ToolChoice = ResponseToolChoice.CreateRequiredChoice() forces tool usage.
  • API key not passed to API: Ensure the OpenAPI spec has proper securitySchemes and security sections configured.

Create a Java agent with OpenAPI tool capabilities

This Java setup can reference MCP tools, but the Java SDK doesn't yet expose a toolbox creation API.

Tip

Recommended: For most agents, add the OpenAPI tool through a toolbox and attach the toolbox to your agent as an MCP tool. Create the toolbox by using the Python, REST API, C#, or TypeScript example, or the Foundry portal, and then reference its MCP endpoint from your Java agent as an McpTool.

The following examples show how to call an OpenAPI tool by using the REST API.

Get an access token:

AGENT_TOKEN=$(az account get-access-token --scope https://ai.azure.com/.default --query accessToken -o tsv)

Anonymous authentication

Add OpenAPI tools through a toolbox, and then attach the toolbox to your agent as an MCP tool. For more information, see What is a toolbox?

  1. Create a toolbox that contains the OpenAPI weather tool:
curl --request POST \
  --url "$FOUNDRY_PROJECT_ENDPOINT/toolboxes/openapi-toolbox/versions?api-version=v1" \
  --header "Foundry-Features: Toolboxes=V1Preview" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "description": "Toolbox with the OpenAPI weather tool",
    "tools": [
      {
        "type": "openapi",
        "openapi": {
          "name": "weather",
          "description": "Tool to get weather data",
          "auth": {
            "type": "project_connection",
            "security_scheme": {
              "project_connection_id": "'$OPENAPI_CONNECTION_ID'"
            }
          },
          "spec": {
            "openapi": "3.1.0",
            "info": {
              "title": "get weather data",
              "description": "Retrieves current weather data for a location.",
              "version": "v1.0.0"
            },
            "servers": [{ "url": "https://wttr.in" }],
            "paths": {
              "/{location}": {
                "get": {
                  "description": "Get weather information for a specific location",
                  "operationId": "GetCurrentWeather",
                  "parameters": [
                    {
                      "name": "location",
                      "in": "path",
                      "description": "City or location to retrieve the weather for",
                      "required": true,
                      "schema": { "type": "string" }
                    },
                    {
                      "name": "format",
                      "in": "query",
                      "description": "Format in which to return data. Always use 3.",
                      "required": true,
                      "schema": { "type": "integer", "default": 3 }
                    }
                  ],
                  "responses": {
                    "200": {
                      "description": "Successful response",
                      "content": {
                        "text/plain": {
                          "schema": { "type": "string" }
                        }
                      }
                    },
                    "404": { "description": "Location not found" }
                  }
                }
              }
            }
          }
        }
      }
    ]
  }'

The toolbox exposes an MCP-compatible endpoint at $FOUNDRY_PROJECT_ENDPOINT/toolboxes/openapi-toolbox/versions/<version>/mcp?api-version=v1, where <version> is the version returned by the previous call.

  1. Create a remote-tool project connection that points at the toolbox endpoint, using a user Entra token so the caller's identity is passed through (audience https://ai.azure.com).
azd ai connection create openapi-toolbox-conn \
  --kind remote-tool \
  --target "$FOUNDRY_PROJECT_ENDPOINT/toolboxes/openapi-toolbox/versions/<version>/mcp?api-version=v1" \
  --auth-type user-entra-token \
  --audience https://ai.azure.com
  1. Create a response that uses the toolbox by attaching it as an MCP tool.

    Set TOOLBOX_CONNECTION_ID to the full resource ID of openapi-toolbox-conn. This connection is separate from the anonymous OpenAPI connection in OPENAPI_CONNECTION_ID. Replace <version> with the version returned when you created the toolbox.

curl --request POST \
  --url "$FOUNDRY_PROJECT_ENDPOINT/openai/v1/responses" \
  --header "Authorization: Bearer $AGENT_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "'$FOUNDRY_MODEL_DEPLOYMENT_NAME'",
    "input": "Use the OpenAPI tool to get the weather in Seattle, WA today.",
    "tool_choice": "required",
    "tools": [
      {
        "type": "mcp",
        "server_label": "toolbox",
        "server_url": "'$FOUNDRY_PROJECT_ENDPOINT'/toolboxes/openapi-toolbox/versions/<version>/mcp?api-version=v1",
        "require_approval": "never",
        "project_connection_id": "'$TOOLBOX_CONNECTION_ID'",
        "headers": {
          "Foundry-Features": "Toolboxes=V1Preview"
        }
      }
    ]
  }'

API key authentication (project connection)

Use this variant only after the anonymous flow succeeds. Download tripadvisor_openapi.json from Before you run the code samples. Configure the API key connection and the specification's securitySchemes and security entries as described in Authenticate with API key. Set OPENAPI_CONNECTION_ID to the full resource ID of that connection, not the anonymous weather connection.

This Bash example uses jq to include the specification in the same remote_tool request shape as the project managed identity samples.

jq -n \
  --arg model "$FOUNDRY_MODEL_DEPLOYMENT_NAME" \
  --arg connection_id "$OPENAPI_CONNECTION_ID" \
  --slurpfile spec tripadvisor_openapi.json \
  '{
    model: $model,
    input: "Recommend five top hotels in the United States.",
    tools: [
      {
        type: "remote_tool",
        tool_arguments: [
          {
            name: "openapi",
            arguments: {
              name: "tripadvisor",
              description: "TripAdvisor travel information.",
              auth: {
                type: "project_connection",
                security_scheme: {
                  project_connection_id: $connection_id
                }
              },
              spec: $spec[0]
            }
          }
        ]
      }
    ],
    tool_choice: "required"
  }' > openapi-api-key-request.json

curl --fail-with-body --request POST \
  --url "${FOUNDRY_PROJECT_ENDPOINT%/}/openai/v1/responses" \
  --header "Authorization: Bearer $AGENT_TOKEN" \
  --header "Content-Type: application/json" \
  --data @openapi-api-key-request.json

For a bearer-token API, keep the same project_connection request shape, but use a connection configured as described in Set up a Bearer token connection. The connection value must start with Bearer followed by a space.

Managed identity authentication

For project managed identity, first create an OpenAPI project connection. Then pass its full resource ID in the Responses request. See the REST example in Call an OpenAPI tool with project managed identity.

Account managed identity is supported only for OpenAPI tools attached directly to prompt agents in existing subscriptions. It's not supported in toolboxes. Use project managed identity for prompt agents too. Migrate existing configurations as soon as possible.

What this code does

This REST API example shows how to call an OpenAPI tool with different authentication methods. The request:

  1. For anonymous authentication, creates a toolbox containing the OpenAPI tool definition and weather API specification.
  2. Creates a response that attaches the toolbox as an MCP tool and asks about Seattle's weather.
  3. Shows an additional direct REST tool definition for API key authentication through a project connection.
  4. The agent calls the API selected by the tool configuration and returns the results.

Required inputs

  • Environment variables: FOUNDRY_PROJECT_ENDPOINT, AGENT_TOKEN, FOUNDRY_MODEL_DEPLOYMENT_NAME.
  • For anonymous auth: OPENAPI_CONNECTION_ID, referencing the anonymous OpenAPI project connection, and TOOLBOX_CONNECTION_ID, referencing the toolbox MCP connection.
  • For API key auth: OPENAPI_CONNECTION_ID, referencing the TripAdvisor API key connection, and tripadvisor_openapi.json.
  • For project managed identity auth: OPENAPI_CONNECTION_ID, as shown in the project managed identity sample.
  • Inline OpenAPI specification in request body.

Expected output

{
  "id": "resp_abc123",
  "object": "response",
  "output": [
    {
      "type": "message",
      "content": [
        {
          "type": "output_text",
          "text": "The weather in Seattle, WA today is cloudy with a temperature of 52°F (11°C)..."
        }
      ]
    }
  ]
}

Common errors

  • 401 Unauthorized: Invalid or missing AGENT_TOKEN, or API key not injected because securitySchemes and security are missing in your OpenAPI spec
  • 404 Not Found: Incorrect endpoint or model deployment name
  • 400 Bad Request: Malformed OpenAPI specification or invalid auth configuration
  • API key not sent with request: Verify the components.securitySchemes section in your OpenAPI spec is properly configured (not empty) and matches your project connection key name

Create an agent with OpenAPI tool capabilities

The following TypeScript code example demonstrates how to create an AI agent with OpenAPI tool capabilities by adding the OpenAPI tool to a toolbox and attaching the toolbox as an MCP tool. The agent can call external APIs defined by OpenAPI specifications. For a JavaScript version of this example, see the sample in the Azure SDK for JavaScript repository on GitHub.

import { DefaultAzureCredential } from "@azure/identity";
import {
  AIProjectClient,
  OpenApiToolboxTool,
  OpenApiFunctionDefinition,
  OpenApiProjectConnectionAuthDetails,
} from "@azure/ai-projects";
import * as fs from "fs";
import * as path from "path";

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Set ${name} before running.`);
  }
  return value;
}
const PROJECT_ENDPOINT = requiredEnv("FOUNDRY_PROJECT_ENDPOINT");
const deploymentName = requiredEnv("FOUNDRY_MODEL_DEPLOYMENT_NAME");
const weatherSpecPath = path.resolve("assets", "weather_openapi.json");

function loadOpenApiSpec(specPath: string): unknown {
  if (!fs.existsSync(specPath)) {
    throw new Error(`OpenAPI specification not found at: ${specPath}`);
  }

  try {
    const data = fs.readFileSync(specPath, "utf-8");
    return JSON.parse(data);
  } catch (error) {
    throw new Error(`Failed to read or parse OpenAPI specification at ${specPath}: ${error}`);
  }
}

function createWeatherTool(spec: unknown): OpenApiToolboxTool {
  const connectionId = process.env.OPENAPI_CONNECTION_ID;
  if (!connectionId) {
    throw new Error("Set OPENAPI_CONNECTION_ID before running.");
  }
  const auth: OpenApiProjectConnectionAuthDetails = {
    type: "project_connection",
    security_scheme: {
      project_connection_id: connectionId,
    },
  };
  const definition: OpenApiFunctionDefinition = {
    name: "get_weather",
    description: "Retrieve weather information for a location using wttr.in",
    spec,
    auth,
  };

  return {
    type: "openapi",
    openapi: definition,
  };
}

export async function main(): Promise<void> {
  const weatherSpec = loadOpenApiSpec(weatherSpecPath);

  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  const weatherTool = createWeatherTool(weatherSpec);

  console.log("Creating a toolbox with the OpenAPI weather tool...");

  // 1. Add the OpenAPI tool to a toolbox. Using a toolbox is the recommended
  //    way to give agents tools. See /azure/foundry/agents/concepts/toolbox-overview
  const toolbox = await project.toolboxes.createVersion(
    "openapi-toolbox",
    [weatherTool],
    { description: "Toolbox with the OpenAPI weather tool" },
  );

  // 2. The toolbox exposes an MCP-compatible endpoint.
  const toolboxMcpUrl =
    `${PROJECT_ENDPOINT}/toolboxes/${toolbox.name}` +
    `/versions/${toolbox.version}/mcp?api-version=v1`;

  // 3. Create a remote-tool project connection that points at the toolbox endpoint.
  //    Use a user Entra token so the caller's identity is passed through
  //    (audience https://ai.azure.com). Create the connection once, for example
  //    with the Azure Developer CLI:
  //
  //    azd ai connection create openapi-toolbox-conn \
  //      --kind remote-tool \
  //      --target "<toolboxMcpUrl>" \
  //      --auth-type user-entra-token \
  //      --audience https://ai.azure.com
  const toolboxConnectionId = process.env.TOOLBOX_CONNECTION_ID;
  if (!toolboxConnectionId) {
    throw new Error("Set TOOLBOX_CONNECTION_ID to the toolbox connection ID.");
  }

  // 4. Attach the toolbox to a prompt agent as an MCP tool.
  const agent = await project.agents.createVersion("MyOpenApiAgent", {
    kind: "prompt",
    model: deploymentName,
    instructions:
      "You are a helpful assistant that can call external APIs defined by OpenAPI specs to answer user questions.",
    tools: [
      {
        type: "mcp",
        server_label: "toolbox",
        server_url: toolboxMcpUrl,
        require_approval: "never",
        project_connection_id: toolboxConnectionId,
        headers: {
          "Foundry-Features": "Toolboxes=V1Preview",
        },
      },
    ],
  });

  // Send a request and stream the response
  const streamResponse = await openai.responses.create(
    {
      input:
        "What's the weather in Seattle and how should I plan my outfit for the day based on the forecast?",
      stream: true,
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        tool_choice: "required",
      },
    },
  );

  // Process the streaming response
  for await (const event of streamResponse) {
    if (event.type === "response.output_text.delta") {
      process.stdout.write(event.delta);
    } else if (event.type === "response.output_text.done") {
      console.log("\n");
    }
  }

  // Clean up resources
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
  process.exitCode = 1;
});

What this code does

This TypeScript example creates an agent with an OpenAPI tool for weather data by using anonymous authentication. When you run the code:

  1. It loads the weather OpenAPI specification from a local JSON file.
  2. Creates a toolbox version containing the weather tool.
  3. Attaches the toolbox to the agent as an MCP tool, then sends a streaming request asking about Seattle's weather and outfit planning.
  4. Processes the streaming response and displays deltas as they arrive.
  5. It forces tool usage by using tool_choice: "required" to ensure the API is called.
  6. Cleans up by deleting the agent.

Required inputs

  • Environment variables: FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, OPENAPI_CONNECTION_ID, and TOOLBOX_CONNECTION_ID.
  • Local file: assets/weather_openapi.json (OpenAPI specification).

Expected output

Creating a toolbox with the OpenAPI weather tool...
The weather in Seattle is <conditions>. Consider wearing <suggestion>.

Common errors

  • Error: OpenAPI specification not found: File path incorrect or file missing
  • AuthenticationError: Invalid Azure credentials
  • API key not working: If switching from anonymous to API key auth, ensure your OpenAPI spec has securitySchemes and security properly configured

Create an agent that uses OpenAPI tools authenticated with a project connection

The following TypeScript code example demonstrates how to create an AI agent that uses OpenAPI tools authenticated through a project connection. The agent loads the TripAdvisor OpenAPI specification from local assets and can invoke the API through the configured project connection. For a JavaScript version of this example, see the sample in the Azure SDK for JavaScript repository on GitHub.

import { DefaultAzureCredential } from "@azure/identity";
import {
  AIProjectClient,
  OpenApiTool,
  OpenApiFunctionDefinition,
  OpenApiProjectConnectionAuthDetails,
} from "@azure/ai-projects";
import * as fs from "fs";
import * as path from "path";

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Set ${name} before running.`);
  }
  return value;
}
const PROJECT_ENDPOINT = requiredEnv("FOUNDRY_PROJECT_ENDPOINT");
const deploymentName = requiredEnv("FOUNDRY_MODEL_DEPLOYMENT_NAME");
const connectionId = requiredEnv("OPENAPI_CONNECTION_ID");
const tripAdvisorSpecPath = path.resolve("assets", "tripadvisor_openapi.json");

function loadOpenApiSpec(specPath: string): unknown {
  if (!fs.existsSync(specPath)) {
    throw new Error(`OpenAPI specification not found at: ${specPath}`);
  }

  try {
    const data = fs.readFileSync(specPath, "utf-8");
    return JSON.parse(data);
  } catch (error) {
    throw new Error(`Failed to read or parse OpenAPI specification at ${specPath}: ${error}`);
  }
}

function createTripAdvisorTool(spec: unknown): OpenApiTool {
  const auth: OpenApiProjectConnectionAuthDetails = {
    type: "project_connection",
    security_scheme: {
      project_connection_id: connectionId,
    },
  };

  const definition: OpenApiFunctionDefinition = {
    name: "get_tripadvisor_location_details",
    description:
      "Fetch TripAdvisor location details, reviews, or photos using the Content API via project connection auth.",
    spec,
    auth,
  };

  return {
    type: "openapi",
    openapi: definition,
  };
}

export async function main(): Promise<void> {
  const tripAdvisorSpec = loadOpenApiSpec(tripAdvisorSpecPath);

  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Create an agent with the OpenAPI project-connection tool
  const agent = await project.agents.createVersion("MyOpenApiConnectionAgent", {
    kind: "prompt",
    model: deploymentName,
    instructions:
      "You are a travel assistant that consults the TripAdvisor Content API via project connection to answer user questions about locations.",
    tools: [createTripAdvisorTool(tripAdvisorSpec)],
  });

  // Send a request and stream the response
  const streamResponse = await openai.responses.create(
    {
      input:
        "Provide a quick overview of the TripAdvisor location 293919 including its name, rating, and review count.",
      stream: true,
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        tool_choice: "required",
      },
    },
  );

  // Process the streaming response
  for await (const event of streamResponse) {
    if (event.type === "response.output_text.delta") {
      process.stdout.write(event.delta);
    } else if (event.type === "response.output_text.done") {
      console.log("\n");
    }
  }

  // Clean up resources
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
  process.exitCode = 1;
});

What this code does

This TypeScript example demonstrates using an OpenAPI tool with API key authentication through a project connection. When you run the code:

  1. It loads the TripAdvisor OpenAPI specification from a local file.
  2. It references the API key connection by using OPENAPI_CONNECTION_ID.
  3. It creates an agent with the TripAdvisor tool that uses the project connection for API key authentication.
  4. It sends a streaming request for TripAdvisor location details.
  5. It forces tool usage by using tool_choice: "required" to ensure the API is called.
  6. It processes and displays the streaming response.
  7. It cleans up by deleting the agent.

Required inputs

  • Environment variables: FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, and OPENAPI_CONNECTION_ID.
  • Local file: ../assets/tripadvisor_openapi.json
  • Project connection configured with TripAdvisor API key

Expected output

Location 293919: <name>, rating: <rating>, review count: <count>.

Common errors

  • Error: OpenAPI specification not found: Check the file path.
  • Connection not found: Verify OPENAPI_CONNECTION_ID is the full resource ID of the API key connection.
  • AuthenticationException: Invalid API key in project connection.
  • API key not injected in requests: Your OpenAPI spec must include proper securitySchemes (under components) and security sections. The key name in securitySchemes must match the key in your project connection.
  • Content type is not supported: Currently, only these two request body content types are supported: application/json and application/json-patch+json. Response content types aren't restricted.

Security and data considerations

When you connect an agent to an OpenAPI tool, the agent can send request parameters derived from user input to the target API.

  • Use project connections for secrets (API keys and tokens). Avoid putting secrets in an OpenAPI spec file or source code.
  • Review what data the API receives and what it returns before you use the tool in production.
  • Use least-privilege access. Assign the project's managed identity only the roles the target service requires.

Authenticate with API key

Use this variant for an API that expects a key in a header or query parameter. You can use only one API key security scheme per OpenAPI tool. If the API requires multiple security schemes, create multiple OpenAPI tools.

  1. Update your OpenAPI spec security schemas. It has a securitySchemes section and one scheme of type apiKey. For example:

     "securitySchemes": {
         "apiKeyHeader": {
                 "type": "apiKey",
                 "name": "x-api-key",
                 "in": "header"
             }
     }
    

    You usually only need to update the name field, which corresponds to the name of key in the connection. If the security schemes include multiple schemes, keep only one of them.

  2. Update your OpenAPI spec to include a security section:

    "security": [
         {  
         "apiKeyHeader": []  
         }  
     ]
    
  3. Remove any parameter in the OpenAPI spec that needs API key, because API key is stored and passed through a connection, as described later in this article.

  4. Create a connection to store your API key.

  5. Go to the Foundry portal and open your project.

  6. Create or select a connection that stores the secret. See Add a new connection to your project.

    Note

    If you regenerate the API key at a later date, you need to update the connection with the new key.

  7. Enter the following information

    • key: name field of your security scheme. In this example, it should be x-api-key

             "securitySchemes": {
                "apiKeyHeader": {
                          "type": "apiKey",
                          "name": "x-api-key",
                          "in": "header"
                      }
              }
      
    • value: YOUR_API_KEY

  8. After you create a connection, you can use it through the SDK or REST API. Use the tabs at the top of this article to see code examples.

Set up a Bearer token connection

Use this variant for an API that expects a bearer token in the Authorization header. It uses the same project_connection auth type as API-key authentication, but the OpenAPI security scheme and connection values differ.

Your OpenAPI spec will look like this:

  BearerAuth:
    type: http
    scheme: bearer
    bearerFormat: JWT

You need to:

  1. Update your OpenAPI spec securitySchemes to use Authorization as the header name:

    "securitySchemes": {
        "bearerAuth": {
            "type": "apiKey",
            "name": "Authorization",
            "in": "header"
        }
    }
    
  2. Add a security section that references the scheme:

    "security": [
        {
            "bearerAuth": []
        }
    ]
    
  3. Create a Custom keys connection in your Foundry project:

    1. Go to the Foundry portal and open your project.
    2. Create or select a connection that stores the secret. See Add a new connection to your project.
    3. Enter the following values:
      • key: Authorization (must match the name field in your securitySchemes)
      • value: Bearer <token> (replace <token> with your actual token)

    Important

The value must include the word Bearer followed by a space before the token. For example: Bearer eyJhbGciOiJSUzI1NiIs.... If you omit the Bearer prefix and following space, the API receives a raw token without the required authorization scheme prefix, and the request fails.

  1. After you create the connection, use it with the project_connection auth type in your code, the same way you would for API key authentication. The connection ID uses the same format: /subscriptions/{{subscriptionID}}/resourceGroups/{{resourceGroupName}}/providers/Microsoft.CognitiveServices/accounts/{{foundryAccountName}}/projects/{{foundryProjectName}}/connections/{{foundryConnectionName}}.

Authenticate by using managed identity (Microsoft Entra ID)

Microsoft Entra ID is a cloud-based identity and access management service that your employees can use to access external resources. By using Microsoft Entra ID, you can add extra security to your APIs without needing to use API keys. When you set up managed identity authentication, the agent authenticates through the Foundry tool it uses.

Important

Managed identity authentication only works when the target service accepts Microsoft Entra ID tokens. If the target API uses a custom authentication scheme that doesn't support Microsoft Entra ID, use API key or Bearer token authentication instead.

Managed identity support

For managed identity authentication, OpenAPI tools in toolboxes have always required the Foundry project's managed identity. This requirement applies to all subscriptions.

For OpenAPI tools attached directly to prompt agents, subscriptions new to OpenAPI tools must use project managed identity. Existing subscriptions support both identities on that path, but project managed identity is recommended. Migrate existing account managed identity configurations as soon as possible.

OpenAPI tool path Subscription Supported managed identity
Tool attached through a toolbox. All subscriptions. Foundry project managed identity only, since toolboxes were introduced. Account managed identity isn't supported.
Tool attached directly to a prompt agent. Subscription new to OpenAPI tools. Foundry project managed identity only. Account managed identity isn't supported.
Tool attached directly to a prompt agent. Existing subscription that has already used OpenAPI tools. Both Foundry account managed identity and Foundry project managed identity. Project managed identity is recommended; migrate from account managed identity as soon as possible.

Assign the project's managed identity the least-privileged role that permits the required API operations on the target service.

The two identities use different authentication configurations:

  • Project managed identity requires an OpenAPI connection in the Foundry project with authType: "ProjectManagedIdentity". Pass that connection's full ARM resource ID in auth.security_scheme.project_connection_id, with auth.type: "project_connection".
  • Account managed identity, supported only for tools attached directly to prompt agents in existing subscriptions, uses auth.type: "managed_identity" and passes the target service's audience directly in the tool definition. This configuration isn't supported in toolboxes, doesn't select the project's managed identity, and isn't the portal's Managed identity option.

Migrate from account to project managed identity

These migration steps apply to OpenAPI tools attached directly to prompt agents in existing subscriptions. Toolboxes already require project managed identity. Use project managed identity for new configurations, and migrate existing prompt-agent account managed identity configurations as soon as possible:

  1. Assign the Foundry project's managed identity the least-privileged role required on the target service. An account managed identity role assignment doesn't apply to the project's identity.
  2. Create an OpenAPI project connection with authType: "ProjectManagedIdentity", the target endpoint, and the audience expected by the target API.
  3. Replace the tool's direct managed_identity audience configuration with auth.type: "project_connection". Pass the connection's full ARM resource ID in auth.security_scheme.project_connection_id.
  4. Call the tool to verify that the project's managed identity can access the target API.
  5. Remove the account identity's target-service role assignment only after you confirm that no other workload needs it.

Understand the audience URI

The audience (sometimes called resource identifier or Application ID URI) tells Microsoft Entra ID which service or API the token is intended to access. The audience value must match what the target service expects, or authentication fails with a 401 error.

Note

The audience is not your Foundry project endpoint. It's the resource identifier of the target service that your OpenAPI tool calls.

The following table lists audience URIs for common Azure services:

Target service Audience URI
Azure Storage https://storage.azure.com
Azure Key Vault https://vault.azure.net
Azure AI Search https://search.azure.com
Azure Translator https://cognitiveservices.azure.com
Azure Logic Apps The audience configured for the workflow's Microsoft Entra ID authorization. See Secure access to logic apps.
Azure API Management (management plane) https://management.azure.com
API protected by a Microsoft Entra app registration (including APIM with OAuth) The Application ID URI from your app registration (for example, api://<client-id>)

Tip

If you use Azure API Management to protect a custom API with an OAuth 2.0 validation policy, the audience is the Application ID URI from the app registration that protects the API — not https://management.azure.com. The management plane audience only applies to Azure Resource Manager operations on the APIM resource itself.

For more information about how agents authenticate with Microsoft Entra ID, see Agent identity and authentication.

Find and verify your audience

Use the following steps to determine and verify the correct audience value:

  • For Azure services: Check the service's documentation for its Microsoft Entra ID resource identifier. Most Azure services list the audience URI in their authentication documentation.
  • For APIs protected by a Microsoft Entra app registration: In the Azure portal, go to Microsoft Entra ID > App registrations > select your app > Expose an API. The Application ID URI at the top of the page is your audience value.
  • To verify a token's audience: Decode the access token at https://jwt.ms and check the aud claim. The aud value must match the audience your target service expects.

Set up managed identity authentication

To set up project managed identity authentication:

  1. Use the Foundry project's managed identity for new configurations. Ensure the project's managed identity is enabled. Account managed identity is a legacy option only for tools attached directly to prompt agents in existing subscriptions; migrate those configurations as soon as possible.
  2. Create or identify the target service that your OpenAPI tool calls.
  3. Assign the required access to the Foundry project's managed identity on the target resource.
    1. Select Access Control for your resource.

    2. Select Add and then add role assignment at the top of the screen.

      Screenshot of the Azure portal showing the Add role assignment action.

    3. Select the least-privileged data-plane or application role that grants the operations in your OpenAPI specification. Azure Resource Manager Reader access alone doesn't grant data-plane access. Then select Next.

    4. Select Managed identity and then select select members.

    5. Select the Foundry project's managed identity.

    6. Select Finish.

  4. Create a project managed identity connection, and pass its full resource ID in the tool definition.

Create a project managed identity connection

Create the connection in the same Foundry project that sends the Responses request. The connection stores the target endpoint and audience, not an API key or access token.

The following Bash example uses Azure CLI and curl to create an OpenAPI connection for Azure Translator in Foundry Tools. Sign in with az login first. Replace the placeholders with your subscription, resource group, Foundry account, project, and Translator resource.

SUB="<subscription-id>"
RESOURCE_GROUP="<resource-group>"
ACCOUNT="<foundry-account-name>"
PROJECT_NAME="<foundry-project-name>"
CONNECTION_NAME="translator-project-mi"
TRANSLATOR_ENDPOINT="https://<translator-resource>.cognitiveservices.azure.com"

PROJECT="/subscriptions/$SUB/resourceGroups/$RESOURCE_GROUP"
PROJECT="$PROJECT/providers/Microsoft.CognitiveServices"
PROJECT="$PROJECT/accounts/$ACCOUNT/projects/$PROJECT_NAME"
export OPENAPI_CONNECTION_ID="$PROJECT/connections/$CONNECTION_NAME"

ARM_TOKEN="$(az account get-access-token \
  --subscription "$SUB" \
  --resource https://management.azure.com \
  --query accessToken -o tsv)"

curl --fail-with-body --request PUT \
  --url "https://management.azure.com$OPENAPI_CONNECTION_ID?api-version=2025-06-01" \
  --header "Authorization: Bearer $ARM_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "properties": {
      "category": "OpenAPI",
      "authType": "ProjectManagedIdentity",
      "target": "'"$TRANSLATOR_ENDPOINT"'/",
      "audience": "https://cognitiveservices.azure.com",
      "metadata": {
        "type": "openapi"
      }
    }
  }'

Reference: Foundry project connection resource schema.

Keep OPENAPI_CONNECTION_ID for the language samples. Use the full connection resource ID, not just the connection name. The audience belongs in the connection; don't pass an account managed identity audience in place of the connection ID.

Call an OpenAPI tool with project managed identity

These samples call Azure Translator through the connection you created. They send an inline OpenAPI specification in a remote_tool payload to the Responses endpoint.

Before you run a sample:

  • Assign the project's managed identity the target service role required for translation.
  • Create the OpenAPI connection with authType: "ProjectManagedIdentity" as described in Create a project managed identity connection.
  • Set FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL_DEPLOYMENT_NAME, and OPENAPI_CONNECTION_ID. The connection must belong to this project.
  • Save the following specification as translator_openapi.json in the directory where you run the sample. Replace <translator-resource> with the resource used in the connection's target.
{
  "openapi": "3.0.1",
  "info": {
    "title": "Azure Translator Service",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://<translator-resource>.cognitiveservices.azure.com/translator/text/v3.0/"
    }
  ],
  "paths": {
    "/translate": {
      "post": {
        "operationId": "Translator_Translate",
        "description": "Translate text into one or more languages.",
        "parameters": [
          {
            "name": "api-version",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "default": "3.0" }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": { "type": "string" }
                  },
                  "required": ["text"]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Translation response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "translations": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "text": { "type": "string" },
                            "to": { "type": "string" }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Reference: Translator translate operation.

The caller authenticates to Foundry with an Azure Identity credential. Foundry resolves authentication to Translator from the project connection and uses the project's managed identity.

Install the dependencies with pip install openai azure-identity.

import json
import os

from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from openai import OpenAI


def main() -> None:
    with open("translator_openapi.json", encoding="utf-8") as spec_file:
        spec = json.load(spec_file)

    tool = {
        "type": "remote_tool",
        "tool_arguments": [
            {
                "name": "openapi",
                "arguments": {
                    "name": "language",
                    "description": "Azure Translator API for text translation.",
                    "default_params": ["api-version"],
                    "auth": {
                        "type": "project_connection",
                        "security_scheme": {
                            "project_connection_id": os.environ[
                                "OPENAPI_CONNECTION_ID"
                            ],
                        },
                    },
                    "spec": spec,
                },
            }
        ],
    }

    with DefaultAzureCredential() as credential:
        token_provider = get_bearer_token_provider(
            credential, "https://ai.azure.com/.default"
        )
        with OpenAI(
            base_url=(
                os.environ["FOUNDRY_PROJECT_ENDPOINT"].rstrip("/")
                + "/openai/v1/"
            ),
            api_key=token_provider,
        ) as client:
            response = client.responses.create(
                model=os.environ["FOUNDRY_MODEL_DEPLOYMENT_NAME"],
                input="Translate 'Hello, how are you?' to Spanish.",
                extra_body={
                    "tools": [tool],
                    "tool_choice": "required",
                },
            )
            print(response.output_text)


if __name__ == "__main__":
    main()

Reference: Azure Identity token provider.

The extra_body argument passes the service-specific remote_tool payload without requiring a typed OpenAPI tool model in the OpenAI SDK.

Use .NET 8 or later, and install the credential library with dotnet add package Azure.Identity. This example sends the service-specific tool payload with HttpClient.

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Azure.Core;
using Azure.Identity;

static string RequiredEnvironmentVariable(string name) =>
    Environment.GetEnvironmentVariable(name)
    ?? throw new InvalidOperationException($"Set {name} before running.");

string endpoint = RequiredEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
string model = RequiredEnvironmentVariable("FOUNDRY_MODEL_DEPLOYMENT_NAME");
string connectionId = RequiredEnvironmentVariable("OPENAPI_CONNECTION_ID");
JsonElement spec = JsonSerializer.Deserialize<JsonElement>(
    File.ReadAllText("translator_openapi.json"));

var tool = new
{
    type = "remote_tool",
    tool_arguments = new[]
    {
        new
        {
            name = "openapi",
            arguments = new
            {
                name = "language",
                description = "Azure Translator API for text translation.",
                default_params = new[] { "api-version" },
                auth = new
                {
                    type = "project_connection",
                    security_scheme = new
                    {
                        project_connection_id = connectionId
                    }
                },
                spec
            }
        }
    }
};

var credential = new DefaultAzureCredential();
AccessToken token = await credential.GetTokenAsync(
    new TokenRequestContext(new[] { "https://ai.azure.com/.default" }));
using var client = new HttpClient();
using var request = new HttpRequestMessage(
    HttpMethod.Post, $"{endpoint.TrimEnd('/')}/openai/v1/responses");
request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", token.Token);
request.Content = JsonContent.Create(new
{
    model,
    input = "Translate 'Hello, how are you?' to Spanish.",
    tools = new[] { tool },
    tool_choice = "required"
});
using HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"HTTP {(int)response.StatusCode}: {responseBody}");
}
Console.WriteLine(responseBody);

Reference: DefaultAzureCredential, HttpClient.

Use Node.js 20 or later, and install the credential library with npm install @azure/identity. Save this JavaScript example as openapi-project-mi.mjs.

import { readFile } from "node:fs/promises";
import { DefaultAzureCredential } from "@azure/identity";

function requiredEnvironmentVariable(name) {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Set ${name} before running.`);
  }
  return value;
}

const endpoint = requiredEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
const model = requiredEnvironmentVariable("FOUNDRY_MODEL_DEPLOYMENT_NAME");
const connectionId = requiredEnvironmentVariable("OPENAPI_CONNECTION_ID");
const spec = JSON.parse(
  await readFile("translator_openapi.json", "utf8"),
);

const tool = {
  type: "remote_tool",
  tool_arguments: [
    {
      name: "openapi",
      arguments: {
        name: "language",
        description: "Azure Translator API for text translation.",
        default_params: ["api-version"],
        auth: {
          type: "project_connection",
          security_scheme: {
            project_connection_id: connectionId,
          },
        },
        spec,
      },
    },
  ],
};

const credential = new DefaultAzureCredential();
const token = await credential.getToken("https://ai.azure.com/.default");
const response = await fetch(
  `${endpoint.replace(/\/$/, "")}/openai/v1/responses`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token.token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model,
      input: "Translate 'Hello, how are you?' to Spanish.",
      tools: [tool],
      tool_choice: "required",
    }),
  },
);
const responseBody = await response.text();
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBody}`);
}
console.log(responseBody);

Reference: DefaultAzureCredential.

Use Java 11 or later. Add com.azure:azure-identity and com.fasterxml.jackson.core:jackson-databind to your Maven dependencies. This example sends the service-specific tool payload with Java's HTTP client.

import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class OpenApiProjectMi {
    private static String requiredEnvironmentVariable(String name) {
        String value = System.getenv(name);
        if (value == null || value.isBlank()) {
            throw new IllegalStateException("Set " + name + " before running.");
        }
        return value;
    }

    public static void main(String[] args) throws Exception {
        String endpoint = requiredEnvironmentVariable(
            "FOUNDRY_PROJECT_ENDPOINT");
        String model = requiredEnvironmentVariable(
            "FOUNDRY_MODEL_DEPLOYMENT_NAME");
        String connectionId = requiredEnvironmentVariable(
            "OPENAPI_CONNECTION_ID");
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> spec = mapper.readValue(
            new File("translator_openapi.json"),
            new TypeReference<Map<String, Object>>() { });

        Map<String, Object> tool = Map.of(
            "type", "remote_tool",
            "tool_arguments", List.of(Map.of(
                "name", "openapi",
                "arguments", Map.of(
                    "name", "language",
                    "description",
                        "Azure Translator API for text translation.",
                    "default_params", List.of("api-version"),
                    "auth", Map.of(
                        "type", "project_connection",
                        "security_scheme", Map.of(
                            "project_connection_id", connectionId)),
                    "spec", spec))));
        Map<String, Object> body = Map.of(
            "model", model,
            "input", "Translate 'Hello, how are you?' to Spanish.",
            "tools", List.of(tool),
            "tool_choice", "required");

        var credential = new DefaultAzureCredentialBuilder().build();
        AccessToken token = Objects.requireNonNull(credential.getToken(
            new TokenRequestContext()
                .addScopes("https://ai.azure.com/.default")).block());
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(endpoint.replaceAll("/$", "")
                + "/openai/v1/responses"))
            .header("Authorization", "Bearer " + token.getToken())
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(
                mapper.writeValueAsString(body)))
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient().send(
            request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            throw new IllegalStateException(
                "HTTP " + response.statusCode() + ": " + response.body());
        }
        System.out.println(response.body());
    }
}

Reference: DefaultAzureCredentialBuilder.

Use Bash, Azure CLI, curl, and jq to build the request from translator_openapi.json. The caller token targets Foundry, not Azure Resource Manager or Translator.

AGENT_TOKEN="$(az account get-access-token \
  --resource https://ai.azure.com \
  --query accessToken -o tsv)"

jq -n \
  --arg model "$FOUNDRY_MODEL_DEPLOYMENT_NAME" \
  --arg connection_id "$OPENAPI_CONNECTION_ID" \
  --slurpfile spec translator_openapi.json \
  '{
    model: $model,
    input: "Translate '\''Hello, how are you?'\'' to Spanish.",
    tools: [
      {
        type: "remote_tool",
        tool_arguments: [
          {
            name: "openapi",
            arguments: {
              name: "language",
              description: "Azure Translator API for text translation.",
              default_params: ["api-version"],
              auth: {
                type: "project_connection",
                security_scheme: {
                  project_connection_id: $connection_id
                }
              },
              spec: $spec[0]
            }
          }
        ]
      }
    ],
    tool_choice: "required"
  }' > openapi-project-mi-request.json

curl --fail-with-body --request POST \
  --url "${FOUNDRY_PROJECT_ENDPOINT%/}/openai/v1/responses" \
  --header "Authorization: Bearer $AGENT_TOKEN" \
  --header "Content-Type: application/json" \
  --data @openapi-project-mi-request.json

Reference: Azure CLI access tokens.

The response contains a Spanish translation of "Hello, how are you?" The Python sample prints the response's text. The HTTP samples print the full JSON response, including the tool output and assistant message.

Troubleshoot common errors

Symptom Likely cause Resolution
API key isn't included in requests. OpenAPI spec missing securitySchemes or security sections. Verify your OpenAPI spec includes both components.securitySchemes and a top-level security section. Ensure the scheme name matches the key name in your project connection.
Agent doesn't call the OpenAPI tool. Tool choice not set or operationId not descriptive. Use tool_choice="required" to force tool invocation. Ensure operationId values are descriptive so the model can choose the right operation.
Authentication fails for project managed identity. Project managed identity isn't enabled, or its role assignment is missing. Verify that the Foundry project's managed identity is enabled and has the target service's least-privileged data-plane or application role for the operations in your OpenAPI specification.
Project managed identity isn't used. Tool uses the direct managed_identity audience configuration instead of a project connection. Create an OpenAPI connection with authType: "ProjectManagedIdentity". Set the tool's auth.type to project_connection and auth.security_scheme.project_connection_id to the full connection resource ID.
Project managed identity returns 401 even though the role is assigned. The connection's audience URI doesn't match what the target service expects. Verify the audience URI in the ProjectManagedIdentity connection against the target service's documentation. For Microsoft Entra ID-protected APIs, use the Application ID URI from your app registration. See Understand the audience URI.
Project managed identity token rejected by target API. Target service doesn't accept Microsoft Entra ID tokens. Confirm the target service supports Microsoft Entra ID authentication. If it doesn't, use an API key or another authentication method supported by the target service.
Request fails with 400 Bad Request. OpenAPI spec doesn't match actual API. Validate your OpenAPI spec against the actual API. Check parameter names, types, and required fields.
Request fails with 401 Unauthorized. API key or token invalid or expired. Regenerate the API key/token and update your project connection. Verify the connection ID is correct.
Tool returns unexpected response format. Response schema not defined in OpenAPI spec. Add response schemas to your OpenAPI spec for better model understanding.
operationId validation error. Invalid characters in operationId. Use only letters, -, and _ in operationId values. Remove numbers and special characters.
Connection not found error. Connection resource ID is incorrect or belongs to another project. Verify OPENAPI_CONNECTION_ID is the full ARM resource ID of the connection in the Foundry project that sends the request.
Bearer token not sent correctly. Connection value is missing the Bearer prefix and following space. Set the connection value to Bearer <token> (with the word Bearer and a space before the token). Verify the OpenAPI spec securitySchemes uses "name": "Authorization".

Choose an authentication method

The following table helps you choose the right authentication method for your OpenAPI tool:

Authentication method Best for Setup complexity
Anonymous Public APIs with no authentication. Requires an OpenAPI project connection with authType: "None". Low
API key Non-Microsoft APIs with key-based access Medium
Managed identity (project managed identity) Azure services and Microsoft Entra ID-protected APIs. Requires a ProjectManagedIdentity connection and the required target-service role assigned to the project's managed identity. Medium-High