หมายเหตุ
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลอง ลงชื่อเข้าใช้หรือเปลี่ยนไดเรกทอรีได้
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลองเปลี่ยนไดเรกทอรีได้
Important
Items marked preview in this article are currently in preview. This preview is provided without a service-level agreement, and Microsoft doesn't recommend it for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.
In this quickstart, you build a toolbox and consume it from a Python hosted agent. The toolbox exposes one Model Context Protocol (MCP) endpoint, so the agent discovers its tools through a single connection.
The Azure Developer CLI and Visual Studio Code workflows use the Foundry toolbox sample. Its azure.yaml declares web search, code interpreter, and MCP sources for Azure REST API specifications, GitHub, Azure Language, and Microsoft Foundry. Three project connections provide the authenticated sources' credentials and identity settings.
The Python SDK workflow creates a smaller toolbox with web search and the public Microsoft Learn MCP server. It uses the sample's agent code without deploying the sample's additional connection and toolbox declarations.
If you use a coding agent like GitHub Copilot, the Microsoft Foundry Skill can help build the toolbox endpoint, connect it to a hosted agent, and adjust the sample tools.
Prerequisites
This quickstart builds on the hosted-agent toolchain. Complete the Prerequisites in the hosted agent quickstart first, which cover the Azure subscription, project roles, Python, the Azure Developer CLI (azd), and the microsoft.foundry extension.
Install Python 3.13 or later and prepare the sample's external dependencies before initialization:
| Input or access | How to prepare it |
|---|---|
GITHUB_MCP_PAT |
Create a GitHub personal access token with only the repository permissions needed by the tools you intend to call. Follow the GitHub MCP server's remote-server setup. Keep the value ready for the initialization prompt. |
AZURE_LANGUAGE_MCP_ENDPOINT |
Set up an Azure Language MCP endpoint. Use the full endpoint, including /language/mcp?api-version=2025-11-15-preview, rather than the resource's base URL. |
| Azure Language access | The sample's langmcpconn connection uses the Foundry project's managed identity. Grant that identity access to the Language resource before invoking its tools. Review Microsoft Entra authentication for tools. For a new project, complete the grant after provisioning creates its identity. |
| Foundry MCP access | The sample's foundrymcpconn connection uses the calling user's Microsoft Entra identity. The user needs access to the resources that the selected Foundry tools operate on. |
The sample doesn't create the external GitHub or Language resources. Initialization prompts for unresolved environment inputs, including the token and Language endpoint, and stores the values in the azd environment. Don't commit credentials, .env files, or .azure.
For the Python SDK path, use the Python section later in this article instead
of the Azure Developer CLI or VS Code workflow. That path creates the
toolbox with project_client.toolboxes.create_version(...), then uploads the
hosted-agent code as a new version and points it at that toolbox by name.
Install the Python packages used in this path:
pip install "azure-ai-projects>=2.3.0" python-dotenv
You need an existing Foundry project with a deployed chat-capable model. The Python SDK path in this quickstart creates the toolbox and the hosted-agent version, but it doesn't scaffold a new Foundry project or create a model deployment for you.
For the .NET SDK path, use the C# section later in this article instead of the Azure Developer CLI or VS Code workflow. That path creates the toolbox with AgentToolboxes.CreateVersion(...), then uploads the C# hosted-agent code as a new version and points it at that toolbox by name.
You also need the .NET 10 SDK or later, and an existing Foundry project with a deployed chat-capable model.
You also need Visual Studio Code with the Microsoft Foundry Toolkit extension, signed in to Azure.
Step 1: Initialize the hosted agent
In a terminal, create an empty directory and initialize the entire sample project into it:
mkdir my-toolbox-agent && cd my-toolbox-agent
azd ai agent init --template "https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/azure.yaml" --src .
Select or create a Foundry project and enter the external input values prepared in Prerequisites. To reuse a model deployment in an existing project, add --model-deployment <existing-deployment-name> to the initialization command. Template adoption doesn't currently provide an existing-deployment picker.
The --src . option selects the project root, not an agent-source subdirectory. Stay in my-toolbox-agent, which now contains azure.yaml, for subsequent azd commands. The agent source remains under src/agent-framework-agent-with-foundry-toolbox-responses.
Review the model declaration and agent settings in azure.yaml before provisioning. To change an external input later, run azd env set <name> <value> from this project root; don't run another azd init.
Open the initialized project folder in Visual Studio Code. Run the following commands in its integrated terminal. This workflow uses the sample's azure.yaml to deploy the connections, toolbox, and agent together; don't create a separate toolbox with the same purpose in the Toolkit.
Step 2: Create the toolbox
The sample declares an agent-tools toolbox as an azure.ai.toolbox service. Its uses entries reference the project and connections; the agent service references the toolbox. Edit these declarations in azure.yaml to change tools or connections.
You don't need a separate toolbox.yaml or a manual azd ai toolbox create command for this workflow. The next step deploys the declarations in dependency order. Provisioning alone doesn't create the toolbox, and local agent startup doesn't create any remote dependencies.
Step 3: Provision Azure resources
Provision the declared infrastructure, and then deploy the connections, toolbox, and hosted agent:
azd up
An existing Foundry project can still need resources declared by the template, such as a model deployment. Review the configuration before running this command. If you created a new project, grant its managed identity access to the Language resource before testing the toolbox.
The toolbox deployment produces TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT. The agent's env declaration maps this versioned endpoint to TOOLBOX_ENDPOINT. Inspect the output from the project root:
azd env get-value TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT
Don't overwrite this binding with an endpoint for a separately created toolbox.
Step 4: Run the agent locally
For the Python agent, ensure its service in azure.yaml includes PYTHONNOUSERSITE: "1" in the existing env map before startup and deployment. Don't rely on loading this setting inside your application. For dependency compatibility guidance, see Configure Python startup.
After the remote dependencies are deployed, start the agent from the project root:
azd ai agent runThis command creates a virtual environment, installs dependencies, and serves the agent on
http://localhost:8088. The service configuration suppliesFOUNDRY_PROJECT_ENDPOINT,AZURE_AI_MODEL_DEPLOYMENT_NAME, andTOOLBOX_ENDPOINT. Don't replace these with placeholder values in a source.envfile.In a separate terminal, from the same project root, inspect the available tools and exercise web search:
azd ai agent invoke --local "List the tools you can use." azd ai agent invoke --local "Find the latest release notes for the Azure CLI on the web."
Step 5: Deploy to Foundry Agent Service
The agent is already deployed by azd up. After changing tools, connections, or agent code, deploy all services together:
azd deploy --all
When the command finishes, the output shows links to the agent playground and the agent endpoint. Invoke the deployed agent:
azd ai agent invoke "List the tools you can use."
The sample uses the versioned endpoint produced by this deployment. This doesn't require promoting the toolbox version to default or redirecting other agents that use an older version.
Python SDK path
Use the following steps if you want to create the toolbox and deploy the hosted-agent version by using the Python SDK instead of the Azure Developer CLI or VS Code flow.
1. Create or choose a Foundry project
- Open Foundry portal and create a Foundry project, or select an existing one.
- In the project, deploy a chat-capable model such as
gpt-5.4-mini. - Copy the project endpoint from Overview and the deployment name from Build > Deployments.
2. Download the toolbox hosted-agent sample
Clone the Foundry samples repo:
git clone https://github.com/microsoft-foundry/foundry-samples.git
Create a working folder for the deployment scripts. In that folder, create a
.env file with these values:
FOUNDRY_PROJECT_ENDPOINT=<your-project-endpoint>
AZURE_AI_MODEL_DEPLOYMENT_NAME=<your-model-deployment-name>
FOUNDRY_HOSTED_AGENT_NAME=toolbox-agent
TOOLBOX_NAME=my-toolbox
FOUNDRY_SAMPLE_PATH=<full-path-to-foundry-samples/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/src/agent-framework-agent-with-foundry-toolbox-responses>
3. Create the toolbox with Python
Create a file named create_toolbox.py in the same working folder as .env:
import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import MCPToolboxTool, WebSearchToolboxTool
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
load_dotenv()
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"].rstrip("/")
toolbox_name = os.environ["TOOLBOX_NAME"]
with (
DefaultAzureCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
):
created = project_client.toolboxes.create_version(
name=toolbox_name,
description="Toolbox with web search and Microsoft Learn MCP.",
tools=[
WebSearchToolboxTool(
name="web_search",
search_context_size="medium",
),
MCPToolboxTool(
server_label="mslearn",
server_url="https://learn.microsoft.com/api/mcp",
require_approval="never",
),
],
)
print(f"Created toolbox version {created.version} for {created.name}")
mcp_endpoint = (
f"{endpoint}/toolboxes/{created.name}/versions/"
f"{created.version}/mcp?api-version=v1"
)
print(f"Toolbox version: {created.version}")
print(f"Toolbox MCP endpoint: {mcp_endpoint}")
Run the script:
python create_toolbox.py
The sample hosted agent can resolve the toolbox either from TOOLBOX_ENDPOINT
or from FOUNDRY_PROJECT_ENDPOINT plus TOOLBOX_NAME. This path uses
TOOLBOX_NAME, so you don't need to store the versioned endpoint in .env.
4. Deploy the hosted agent with Python
Create a file named deploy_toolbox_agent.py in the same working folder as
.env:
import os
import tempfile
import time
import zipfile
from pathlib import Path
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
AgentEndpointConfig,
CodeConfiguration,
CodeDependencyResolution,
FixedRatioVersionSelectionRule,
HostedAgentDefinition,
ProtocolConfiguration,
ProtocolVersionRecord,
ResponsesProtocolConfiguration,
VersionSelector,
)
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
load_dotenv()
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
model_name = os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
agent_name = os.environ.get("FOUNDRY_HOSTED_AGENT_NAME", "toolbox-agent")
toolbox_name = os.environ["TOOLBOX_NAME"]
sample_path = Path(os.environ["FOUNDRY_SAMPLE_PATH"]).resolve()
def create_code_zip(source_dir: Path) -> Path:
zip_path = Path(tempfile.gettempdir()) / f"{agent_name}.zip"
excluded = {".git", ".venv", "__pycache__", ".env"}
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zip_file:
for path in source_dir.rglob("*"):
if not path.is_file():
continue
if any(part in excluded for part in path.parts):
continue
zip_file.write(path, path.relative_to(source_dir))
return zip_path
def wait_for_active_version(project_client: AIProjectClient, version: str) -> None:
for attempt in range(60):
time.sleep(10)
details = project_client.agents.get_version(
agent_name=agent_name,
agent_version=version,
)
status = details["status"]
print(f"Provisioning status: {status} (attempt {attempt + 1}/60)")
if status == "active":
return
if status == "failed":
raise RuntimeError(f"Hosted agent provisioning failed: {dict(details)}")
raise RuntimeError("Timed out waiting for the hosted agent version to become active.")
code_zip_path = create_code_zip(sample_path)
with (
code_zip_path.open("rb") as code_stream,
DefaultAzureCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
):
original_agent_endpoint = None
created = None
try:
created = project_client.agents.create_version_from_code(
agent_name=agent_name,
description="Hosted agent with Foundry Toolbox integration.",
definition=HostedAgentDefinition(
cpu="1",
memory="2Gi",
code_configuration=CodeConfiguration(
runtime="python_3_13",
entry_point=["python", "main.py"],
dependency_resolution=CodeDependencyResolution.REMOTE_BUILD,
),
environment_variables={
"FOUNDRY_PROJECT_ENDPOINT": endpoint,
"AZURE_AI_MODEL_DEPLOYMENT_NAME": model_name,
"TOOLBOX_NAME": toolbox_name,
"PYTHONNOUSERSITE": "1",
},
protocol_versions=[
ProtocolVersionRecord(protocol="responses", version="2.0.0")
],
),
code=code_stream,
)
print(f"Created hosted agent version {created.version}")
wait_for_active_version(project_client, created.version)
original_agent_endpoint = project_client.agents.get(
agent_name=agent_name
).agent_endpoint
project_client.agents.update_details(
agent_name=agent_name,
agent_endpoint=AgentEndpointConfig(
version_selector=VersionSelector(
version_selection_rules=[
FixedRatioVersionSelectionRule(
agent_version=created.version,
traffic_percentage=100,
),
]
),
protocol_configuration=ProtocolConfiguration(
responses=ResponsesProtocolConfiguration()
),
),
)
with project_client.get_openai_client(agent_name=agent_name) as openai_client:
response = openai_client.responses.create(
input=(
"How do I create a hosted agent in Microsoft Foundry? "
"Use the Microsoft Learn documentation."
),
)
if response.status != "completed":
raise RuntimeError(f"Agent invocation failed: {response.error}")
print(response.output_text)
finally:
if original_agent_endpoint is not None:
project_client.agents.update_details(
agent_name=agent_name,
agent_endpoint=original_agent_endpoint,
)
if created is not None:
project_client.agents.delete_version(
agent_name=agent_name,
agent_version=created.version,
force=True,
)
Run the script:
python deploy_toolbox_agent.py
This script uploads the toolbox sample as a new hosted-agent version, points the hosted agent at that version temporarily, invokes it with a Microsoft Learn question, and restores the previous endpoint configuration when it finishes.
5. Verify the toolbox-backed response
If you configure the toolbox correctly, the response shows that the hosted agent discovered the toolbox tools and answered by using Microsoft Learn documentation.
C# SDK path
Use this path to create the toolbox and deploy the C# hosted-agent sample with the .NET SDK instead of the Azure Developer CLI or VS Code workflow.
1. Create or choose a Foundry project
- Open Foundry portal and create a Foundry project, or select an existing one.
- In the project, deploy a chat-capable model such as
gpt-4o. - Copy the project endpoint from Overview and the deployment name from Build > Deployments.
2. Download the toolbox hosted-agent sample
Clone the Foundry samples repo:
git clone https://github.com/microsoft-foundry/foundry-samples.git
The C# hosted-agent sample is under
samples/csharp/hosted-agents/agent-framework/foundry-toolbox-server-side/src/foundry-toolbox-server-side-dotnet-agent-framework.
The deployment code in the next steps sets these environment variables on the
container:
| Variable | Description |
|---|---|
FOUNDRY_PROJECT_ENDPOINT |
Foundry project endpoint. |
AZURE_AI_MODEL_DEPLOYMENT_NAME |
Chat model deployment name. |
TOOLBOX_NAME |
Toolbox name the agent connects to. |
3. Create the toolbox with C#
Create a .NET console app and install the packages. Toolbox APIs are in preview,
so install the prerelease Azure.AI.Projects package:
dotnet new console --name create-toolbox
cd create-toolbox
dotnet add package Azure.AI.Projects --prerelease
dotnet add package Azure.Identity
Replace Program.cs with the following code and set endpoint to your project
endpoint:
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using OpenAI;
using OpenAI.Responses;
#pragma warning disable AAIP001, OPENAI001
var endpoint = "https://<account>.services.ai.azure.com/api/projects/<project>";
var toolboxName = "my-toolbox";
AIProjectClient projectClient = new(new Uri(endpoint), new DefaultAzureCredential());
AgentToolboxes toolboxes = projectClient.AgentAdministrationClient.GetAgentToolboxes();
ToolboxVersion created = toolboxes.CreateVersion(
name: toolboxName,
tools:
[
new WebSearchToolboxTool { Name = "web_search", SearchContextSize = WebSearchToolSearchContextSize.Medium },
new MCPToolboxTool(serverLabel: "mslearn")
{
ServerUri = new Uri("https://learn.microsoft.com/api/mcp"),
ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.NeverRequireApproval),
},
],
description: "Toolbox with web search and Microsoft Learn MCP.");
Console.WriteLine($"Created toolbox version {created.Version} for {created.Name}");
Run the app:
dotnet run
The sample hosted agent resolves the toolbox from FOUNDRY_PROJECT_ENDPOINT
plus TOOLBOX_NAME, so you don't need to store the versioned endpoint.
4. Deploy the hosted agent with C#
Create a second console app for the deployment code:
dotnet new console --name deploy-toolbox-agent
cd deploy-toolbox-agent
dotnet add package Azure.AI.Projects --prerelease
dotnet add package Azure.AI.Extensions.OpenAI
dotnet add package Azure.Identity
Replace Program.cs with the following code. Set endpoint, chatModel, and
samplePath to your values. samplePath is the full path to the
foundry-toolbox-server-side-dotnet-agent-framework source folder you cloned in
Step 2:
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using OpenAI.Responses;
#pragma warning disable AAIP001, OPENAI001
var endpoint = "https://<account>.services.ai.azure.com/api/projects/<project>";
var chatModel = "gpt-4o";
var toolboxName = "my-toolbox";
var agentName = "toolbox-agent";
var samplePath =
@"<path-to-foundry-samples>\samples\csharp\hosted-agents\agent-framework\foundry-toolbox-server-side\src\foundry-toolbox-server-side-dotnet-agent-framework";
AIProjectClient projectClient = new(new Uri(endpoint), new DefaultAzureCredential());
var agentsClient = projectClient.AgentAdministrationClient;
HostedAgentDefinition definition = new(cpu: "1", memory: "2Gi")
{
Versions = { new ProtocolVersionRecord(ProjectsAgentProtocol.Responses, "2.0.0") },
CodeConfiguration = new(
runtime: "dotnet_10",
entryPoint: ["dotnet", "foundry-toolbox-server-side.dll"],
dependencyResolution: CodeDependencyResolution.RemoteBuild),
};
definition.EnvironmentVariables.Add("FOUNDRY_PROJECT_ENDPOINT", endpoint);
definition.EnvironmentVariables.Add("AZURE_AI_MODEL_DEPLOYMENT_NAME", chatModel);
definition.EnvironmentVariables.Add("TOOLBOX_NAME", toolboxName);
ProjectsAgentVersion? created = null;
AgentEndpointConfiguration? originalEndpoint = null;
try
{
created = agentsClient.CreateAgentVersionFromCode(
agentName, samplePath, new AgentVersionFromCodeMetadata(definition));
Console.WriteLine($"Created hosted agent version {created.Version}");
for (var attempt = 1; attempt <= 60; attempt++)
{
Thread.Sleep(TimeSpan.FromSeconds(10));
created = agentsClient.GetAgentVersion(agentName, created.Version);
Console.WriteLine($"Provisioning status: {created.Status} (attempt {attempt}/60)");
if (created.Status == AgentVersionStatus.Active) break;
if (created.Status == AgentVersionStatus.Failed)
throw new InvalidOperationException("Hosted agent provisioning failed.");
}
ProjectsAgentRecord agent = agentsClient.GetAgent(agentName);
originalEndpoint = agent.AgentEndpoint;
agentsClient.PatchAgent(agentName, new PatchAgentOptions
{
AgentEndpoint = new AgentEndpointConfiguration
{
VersionSelector = new([new FixedRatioVersionSelectionRule(created.Version, 100)]),
ProtocolConfiguration = new() { Responses = new ResponsesProtocolConfiguration() },
},
});
ProjectResponsesClient responsesClient = projectClient.ProjectOpenAIClient
.GetProjectResponsesClientForAgentEndpoint(agentName);
ResponseResult response = responsesClient.CreateResponse(
"How do I create a hosted agent in Microsoft Foundry? Use the Microsoft Learn documentation.");
Console.WriteLine(response.GetOutputText());
}
finally
{
if (originalEndpoint is not null)
agentsClient.PatchAgent(agentName, new PatchAgentOptions { AgentEndpoint = originalEndpoint });
if (created is not null)
agentsClient.DeleteAgentVersion(agentName, created.Version, force: true);
}
Run the app:
dotnet run
This code uploads the toolbox sample as a new hosted-agent version, points the hosted agent at that version temporarily, invokes it with a Microsoft Learn question, and restores the previous endpoint configuration when it finishes.
5. Verify the toolbox-backed response
If you configure the toolbox correctly, the response shows that the hosted agent discovered the toolbox tools and answered by using Microsoft Learn documentation.
Clean up resources
Delete the resources when you're finished so you stop incurring charges.
Delete the toolbox:
azd ai toolbox delete agent-tools --force
After you delete the toolbox, its endpoint stops working. Stop the local agent and remove any copied endpoint from local .env files. Running azd deploy --all again recreates the toolbox declared in azure.yaml.
Delete the agent and its Azure resources:
Warning
If the current azd environment created the Foundry project, azd down permanently deletes the project's resource group and everything in it. If you selected an existing project during initialization, azd down leaves the project, its resource group, the hosted agent, and other quickstart resources in place. To delete resources you no longer need from the existing project, delete them separately.
azd down
Delete the toolbox by name:
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from dotenv import load_dotenv
load_dotenv()
with (
DefaultAzureCredential() as credential,
AIProjectClient(
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=credential,
) as project_client,
):
project_client.toolboxes.delete(name=os.environ["TOOLBOX_NAME"])
If you created a dedicated resource group or project for this quickstart, delete it from the Azure portal after you no longer need the toolbox, chat deployment, or hosted agent.
The deployment code already deletes the hosted agent version and restores the
previous endpoint configuration when it finishes. To delete the toolbox, add
this code to a console app that has the Azure.AI.Projects (prerelease) and
Azure.Identity packages installed:
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
#pragma warning disable AAIP001
var endpoint = "https://<account>.services.ai.azure.com/api/projects/<project>";
var toolboxName = "my-toolbox";
AIProjectClient projectClient = new(new Uri(endpoint), new DefaultAzureCredential());
projectClient.AgentAdministrationClient.GetAgentToolboxes().Delete(toolboxName);
Console.WriteLine($"Deleted toolbox '{toolboxName}'.");
If you created a dedicated resource group or project for this quickstart, delete it from the Azure portal after you no longer need the toolbox, chat deployment, or hosted agent.
Troubleshooting
| Issue | Solution |
|---|---|
azd env set reports that no project exists |
Run the command from the initialized directory containing azure.yaml. With the commands in this article, that directory is my-toolbox-agent. |
| Initialization requests a GitHub token or Language endpoint | Prepare the external input values in Prerequisites. The full CLI sample uses more tool sources than the Python SDK workflow. |
| The agent starts but has no toolbox endpoint | Complete azd up before a local CLI run. Check TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT and the agent's TOOLBOX_ENDPOINT binding in azure.yaml. For the Python SDK workflow, check TOOLBOX_NAME. |
| Tool discovery fails for one source | Check the failing source's connection, service availability, and permissions. A failing source can prevent enumeration of the entire toolbox. |
| Calls to the toolbox endpoint fail with an authorization error | Confirm every request includes an Entra token scoped to https://ai.azure.com/.default. The sample handles this for you. |
Connection refused on local run |
Ensure no other process is using port 8088. |
What you learned
In this quickstart, you:
- Built a toolbox that combines multiple tools behind one endpoint.
- Consumed the toolbox from a Python hosted agent that connects over the Model Context Protocol by using Azure Developer CLI or the Python SDK.
- Ran the agent locally or validated it remotely and deployed it to Foundry Agent Service.