Skip to content

Commit 76db669

Browse files
howieleungnick863jhakulinglharperCopilot
authored
Feature/azure ai agents/1.1.0b4 (#41902)
* Add note about standard agent setup (#41877) * use bing resource name * update sample snippet for deep research (#41884) * [AI Agents] add MCPTool class and sample (#41886) * [AI Agents] initial code gen * update patch files, add sample * remove call debug output from sample * set default require_approval to "always" * update aio patch with tool_approvals * review, build feedback * more review feedback * review feedback * update changelog * review feedback * Howie/auto func sample 2 (#41901) * add auto function call sample (#41885) * update * Update sample_agents_auto_function_call.py * added async sample and use project client * update * fix spelling * update change log * Update CHANGELOG.md * update version * update * update version * Fix OpenApi Tool * resolved comment * Update * fix code to pass test * update * update * update * update * update * Made AgentsOperationsMixin private (#41900) * update samples for preview tools (#41922) * update commit hash to matching TypeSpec branch * Update sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_azure_functions.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Changelog with MCP and runs.create changes * update README and TypeSpec commit * updating tracing documentation in readme (#41953) * updating tracing documentation in readme * fixing spelling error * change to restart build * Update CHANGELOG.md * adding response format samples (#41944) * adding response format samples * removing code snippet tags * updating samples * removing unwanted change * Update docstring using AI (#41979) * Update docstring using AI * resolved comments * Update CHANGELOG.md --------- Co-authored-by: Nikolay Rovinskiy <30440255+nick863@users.noreply.github.com> Co-authored-by: jhakulin <jhakulin@microsoft.com> Co-authored-by: Glenn Harper <64209257+glharper@users.noreply.github.com> Co-authored-by: Glenn Harper <glharper@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: M-Hietala <78813398+M-Hietala@users.noreply.github.com>
1 parent 5b185b2 commit 76db669

34 files changed

+1691
-284
lines changed

sdk/ai/azure-ai-agents/CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22

33
# Release History
44

5+
## 1.1.0b4 (2025-07-11)
6+
7+
### Features Added
8+
9+
- Added support for MCP tool. For more information, see https://aka.ms/FoundryAgentMCPDoc.
10+
- New tool_resources parameter added to runs.create method. This parameter represents overridden enabled tool resources that the agent should use to run
11+
the thread. Default value is None.
12+
13+
### Bugs Fixed
14+
15+
- `_AgentsClientOperationsMixin` now it is private.
16+
17+
### Sample updates
18+
19+
- Added a sample showing usage of MCP tool, [`sample_agents_mcp.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_mcp.py).
20+
- Added a sample showing auto function call for a synchronous client, [`sample_agents_auto_function_call.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_auto_function_call.py)
21+
- Added a sample showing auto function call for an asynchronous client, [`sample_agents_auto_function_call_async.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_async/sample_agents_auto_function_call_async.py).
22+
23+
524
## 1.1.0b3 (2025-06-30)
625

726
### Features Added

sdk/ai/azure-ai-agents/README.md

Lines changed: 171 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ To report an issue with the client library, or request additional features, plea
3939
- [Fabric data](#create-an-agent-with-fabric)
4040
- [Connected agents](#create-an-agent-using-another-agents)
4141
- [Deep Research](#create-agent-with-deep-research)
42+
- [MCP](#create-agent-with-mcp)
4243
- [Create thread](#create-thread) with
4344
- [Tool resource](#create-thread-with-tool-resource)
4445
- [Create message](#create-message) with:
@@ -52,7 +53,9 @@ To report an issue with the client library, or request additional features, plea
5253
- [Tracing](#tracing)
5354
- [Installation](#installation)
5455
- [How to enable tracing](#how-to-enable-tracing)
56+
- [Enabling content recording](#enabling-content-recording)
5557
- [How to trace your own functions](#how-to-trace-your-own-functions)
58+
- [Adding custom attributes to spans](#adding-custom-attributes-to-spans)
5659
- [Troubleshooting](#troubleshooting)
5760
- [Logging](#logging)
5861
- [Reporting issues](#reporting-issues)
@@ -374,7 +377,7 @@ with project_client:
374377

375378
### Create Agent with Deep Research
376379

377-
To enable your Agent to do a detailed research of a topic, use the `DeepResearchTool` along with a connection to a Bing Grounding resource.
380+
To enable your Agent to do detailed research of a topic, use the `DeepResearchTool` along with a connection to a Bing Grounding resource.
378381
This scenarios requires you to specify two model deployments. One is the generic chat model that does arbitration, and is
379382
specified as usual when you call the `create_agent` method. The other is the Deep Research model, which is specified
380383
when you define the `DeepResearchTool`.
@@ -384,7 +387,7 @@ Here is an example:
384387
<!-- SNIPPET:sample_agents_deep_research.create_agent_with_deep_research_tool -->
385388

386389
```python
387-
conn_id = os.environ["AZURE_BING_CONNECTION_ID"]
390+
conn_id = project_client.connections.get(name=os.environ["BING_RESOURCE_NAME"]).id
388391

389392
# Initialize a Deep Research tool with Bing Connection ID and Deep Research model deployment name
390393
deep_research_tool = DeepResearchTool(
@@ -413,46 +416,128 @@ with project_client:
413416
> **Limitation**: The Deep Research tool is currently recommended **only** in non-streaming scenarios.
414417
> Using it with streaming can work, but it may occasionally time-out and is therefore not yet recommended.
415418
416-
### Create Agent with Azure AI Search
419+
### Create Agent with MCP
417420

418-
Azure AI Search is an enterprise search system for high-performance applications. It integrates with Azure OpenAI Service and Azure Machine Learning, offering advanced search technologies like vector search and full-text search. Ideal for knowledge base insights, information discovery, and automation. Creating an Agent with Azure AI Search requires an existing Azure AI Search Index. For more information and setup guides, see [Azure AI Search Tool Guide](https://learn.microsoft.com/azure/ai-services/agents/how-to/tools/azure-ai-search?tabs=azurecli%2Cpython&pivots=overview-azure-ai-search).
421+
To enable your Agent to connect to a MCP server, use the `McpTool` along with a server URI to a MCP server and a label for that server.
422+
Note that approval to send data to that server is required by default (but can be set to not required for each run).
419423

420-
Here is an example to integrate Azure AI Search:
424+
Here is an example:
421425

422-
<!-- SNIPPET:sample_agents_azure_ai_search.create_agent_with_azure_ai_search_tool -->
426+
<!-- SNIPPET:sample_agents_mcp.create_agent_with_mcp_tool -->
423427

424428
```python
425-
with AIProjectClient(
426-
endpoint=os.environ["PROJECT_ENDPOINT"],
427-
credential=DefaultAzureCredential(),
428-
) as project_client:
429-
conn_id = project_client.connections.get_default(ConnectionType.AZURE_AI_SEARCH).id
430-
431-
print(conn_id)
432-
433-
# Initialize agent AI search tool and add the search index connection id
434-
ai_search = AzureAISearchTool(
435-
index_connection_id=conn_id,
436-
index_name="sample_index",
437-
query_type=AzureAISearchQueryType.SIMPLE,
438-
top_k=3,
439-
filter="",
440-
)
429+
# Initialize agent MCP tool
430+
mcp_tool = McpTool(
431+
server_label=mcp_server_label,
432+
server_url=mcp_server_url,
433+
allowed_tools=[], # Optional: specify allowed tools
434+
)
435+
436+
# You can also add or remove allowed tools dynamically
437+
search_api_code = "search_azure_rest_api_code"
438+
mcp_tool.allow_tool(search_api_code)
439+
print(f"Allowed tools: {mcp_tool.allowed_tools}")
441440

442-
# Create agent with AI search tool and process agent run
441+
# Create agent with MCP tool and process agent run
442+
with project_client:
443443
agents_client = project_client.agents
444444

445+
# Create a new agent.
446+
# NOTE: To reuse existing agent, fetch it with get_agent(agent_id)
445447
agent = agents_client.create_agent(
446448
model=os.environ["MODEL_DEPLOYMENT_NAME"],
447-
name="my-agent",
448-
instructions="You are a helpful agent",
449-
tools=ai_search.definitions,
450-
tool_resources=ai_search.resources,
449+
name="my-mcp-agent",
450+
instructions="You are a helpful agent that can use MCP tools to assist users. Use the available MCP tools to answer questions and perform tasks.",
451+
tools=mcp_tool.definitions,
451452
)
452453
```
453454

454455
<!-- END SNIPPET -->
455456

457+
The tool approval flow looks like this:
458+
459+
<!-- SNIPPET:sample_agents_mcp.handle_tool_approvals -->
460+
461+
```python
462+
# Create and process agent run in thread with MCP tools
463+
mcp_tool.update_headers("SuperSecret", "123456")
464+
# mcp_tool.set_approval_mode("never") # Uncomment to disable approval requirement
465+
run = agents_client.runs.create(thread_id=thread.id, agent_id=agent.id, tool_resources=mcp_tool.resources)
466+
print(f"Created run, ID: {run.id}")
467+
468+
while run.status in ["queued", "in_progress", "requires_action"]:
469+
time.sleep(1)
470+
run = agents_client.runs.get(thread_id=thread.id, run_id=run.id)
471+
472+
if run.status == "requires_action" and isinstance(run.required_action, SubmitToolApprovalAction):
473+
tool_calls = run.required_action.submit_tool_approval.tool_calls
474+
if not tool_calls:
475+
print("No tool calls provided - cancelling run")
476+
agents_client.runs.cancel(thread_id=thread.id, run_id=run.id)
477+
break
478+
479+
tool_approvals = []
480+
for tool_call in tool_calls:
481+
if isinstance(tool_call, RequiredMcpToolCall):
482+
try:
483+
print(f"Approving tool call: {tool_call}")
484+
tool_approvals.append(
485+
ToolApproval(
486+
tool_call_id=tool_call.id,
487+
approve=True,
488+
headers=mcp_tool.headers,
489+
)
490+
)
491+
except Exception as e:
492+
print(f"Error approving tool_call {tool_call.id}: {e}")
493+
494+
print(f"tool_approvals: {tool_approvals}")
495+
if tool_approvals:
496+
agents_client.runs.submit_tool_outputs(
497+
thread_id=thread.id, run_id=run.id, tool_approvals=tool_approvals
498+
)
499+
500+
print(f"Current run status: {run.status}")
501+
```
502+
503+
<!-- END SNIPPET -->
504+
505+
### Create Agent with Azure AI Search
506+
507+
Azure AI Search is an enterprise search system for high-performance applications. It integrates with Azure OpenAI Service and Azure Machine Learning, offering advanced search technologies like vector search and full-text search. Ideal for knowledge base insights, information discovery, and automation. Creating an Agent with Azure AI Search requires an existing Azure AI Search Index. For more information and setup guides, see [Azure AI Search Tool Guide](https://learn.microsoft.com/azure/ai-services/agents/how-to/tools/azure-ai-search?tabs=azurecli%2Cpython&pivots=overview-azure-ai-search).
508+
509+
Here is an example to integrate Azure AI Search:
510+
511+
<!-- SNIPPET:sample_agents_azure_ai_search.create_agent_with_azure_ai_search_tool -->
512+
513+
```python
514+
conn_id = project_client.connections.get_default(ConnectionType.AZURE_AI_SEARCH).id
515+
516+
print(conn_id)
517+
518+
# Initialize agent AI search tool and add the search index connection id
519+
ai_search = AzureAISearchTool(
520+
index_connection_id=conn_id,
521+
index_name="sample_index",
522+
query_type=AzureAISearchQueryType.SIMPLE,
523+
top_k=3,
524+
filter="",
525+
)
526+
527+
# Create agent with AI search tool and process agent run
528+
agents_client = project_client.agents
529+
530+
agent = agents_client.create_agent(
531+
model=os.environ["MODEL_DEPLOYMENT_NAME"],
532+
name="my-agent",
533+
instructions="You are a helpful agent",
534+
tools=ai_search.definitions,
535+
tool_resources=ai_search.resources,
536+
)
537+
```
538+
539+
<!-- END SNIPPET -->
540+
456541
If the agent has found the relevant information in the index, the reference
457542
and annotation will be provided in the message response. In the example above, we replace
458543
the reference placeholder by the actual reference and url. Please note, that to
@@ -531,8 +616,12 @@ agent = await agents_client.create_agent(
531616

532617
<!-- END SNIPPET -->
533618

534-
Notice that if `enable_auto_function_calls` is called, the SDK will invoke the functions automatically during `create_and_process` or streaming. If you prefer to execute them manually, refer to [`sample_agents_stream_eventhandler_with_functions.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_streaming/sample_agents_stream_eventhandler_with_functions.py) or
535-
[`sample_agents_functions.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_functions.py)
619+
When `enable_auto_function_calls` is called, the SDK will automatically invoke functions during both `create_and_process` and streaming workflows. This simplifies agent logic by handling function execution internally. Furthermore, although function tools and definitions are preserved in Agent service, their function implements are not. Therefore, if your code queries earlier created agents through `update_agents` or `get_agents` function, you MUST also provide the function implementations through `enable_auto_function_calls` to complete auto function callings.
620+
621+
- For examples of automatic function calls in action, refer to [`sample_agents_auto_function_call.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_auto_function_call.py) or [`sample_agents_auto_function_call_async.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_async/sample_agents_auto_function_call_async.py).
622+
- If you prefer to manage function execution manually, refer to [`sample_agents_stream_eventhandler_with_functions.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_streaming/sample_agents_stream_eventhandler_with_functions.py) or
623+
[`sample_agents_functions.py`](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-agents/samples/agents_tools/sample_agents_functions.py).
624+
536625

537626
### Create Agent With Azure Function Call
538627

@@ -634,6 +723,7 @@ def foo(arguments: func.QueueMessage, outputQueue: func.Out[str]) -> None:
634723
To deploy your function to Azure properly, follow Microsoft's official documentation step by step:
635724

636725
[Azure Functions Python Developer Guide](https://learn.microsoft.com/azure/azure-functions/create-first-function-cli-python?tabs=windows%2Cbash%2Cazure-cli%2Cbrowser)
726+
**Note:** The Azure Function may be only used in standard agent setup. Please follow the [instruction](https://github.com/azure-ai-foundry/foundry-samples/tree/main/samples/microsoft/infrastructure-setup/41-standard-agent-setup) to deploy an agent, capable of calling Azure Functions.
637727

638728
**Summary of required steps:**
639729

@@ -695,13 +785,6 @@ Below is an example of how to create an Azure Logic App utility tool and registe
695785
<!-- SNIPPET:sample_agents_logic_apps.register_logic_app -->
696786

697787
```python
698-
699-
# Create the agents client
700-
project_client = AIProjectClient(
701-
endpoint=os.environ["PROJECT_ENDPOINT"],
702-
credential=DefaultAzureCredential(),
703-
)
704-
705788
# Extract subscription and resource group from the project scope
706789
subscription_id = os.environ["SUBSCRIPTION_ID"]
707790
resource_group = os.environ["resource_group_name"]
@@ -951,9 +1034,11 @@ To understand what calls were made by the main agent to the connected ones, we w
9511034
for run_step in agents_client.run_steps.list(thread_id=thread.id, run_id=run.id, order=ListSortOrder.ASCENDING):
9521035
if isinstance(run_step.step_details, RunStepToolCallDetails):
9531036
for tool_call in run_step.step_details.tool_calls:
954-
print(f"\tAgent: {tool_call._data['connected_agent']['name']} "
955-
f"query: {tool_call._data['connected_agent']['arguments']} ",
956-
f"output: {tool_call._data['connected_agent']['output']}")
1037+
print(
1038+
f"\tAgent: {tool_call._data['connected_agent']['name']} "
1039+
f"query: {tool_call._data['connected_agent']['arguments']} ",
1040+
f"output: {tool_call._data['connected_agent']['output']}",
1041+
)
9571042
```
9581043

9591044
<!-- END SNIPPET -->
@@ -968,7 +1053,7 @@ messages = agents_client.messages.list(thread_id=thread.id, order=ListSortOrder.
9681053
for msg in messages:
9691054
if msg.text_messages:
9701055
last_text = msg.text_messages[-1]
971-
text = last_text.text.value.replace('\u3010', '[').replace('\u3011', ']')
1056+
text = last_text.text.value.replace("\u3010", "[").replace("\u3011", "]")
9721057
print(f"{msg.role}: {text}")
9731058
```
9741059

@@ -1481,6 +1566,14 @@ from azure.ai.agents.telemetry import enable_telemetry
14811566

14821567
enable_telemetry(destination=sys.stdout)
14831568
```
1569+
1570+
### Enabling content recording
1571+
Content recording controles whether message contents and tool call related details, such as parameters and return values, are captured with the traces.
1572+
To enable content recording set the `AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED` environment variable value to `true`. If the environment variable is not set, then the value will default to `false`.
1573+
1574+
1575+
**Important:** The `AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED` environment variable only controls content recording for built-in agent traces. When you use the `@trace_function` decorator on your own functions, all parameters and return values are always traced.
1576+
14841577
### How to trace your own functions
14851578

14861579
The decorator `trace_function` is provided for tracing your own function calls using OpenTelemetry. By default the function name is used as the name for the span. Alternatively you can provide the name for the span as a parameter to the decorator.
@@ -1496,6 +1589,44 @@ Object types are omitted, and the corresponding parameter is not traced.
14961589

14971590
The parameters are recorded in attributes `code.function.parameter.<parameter_name>` and the return value is recorder in attribute `code.function.return.value`
14981591

1592+
### Adding custom attributes to spans
1593+
1594+
Define your own span processor which adds your custom attributes:
1595+
1596+
<!-- SNIPPET:sample_agents_basics_with_console_tracing_custom_attributes.custom_attribute_span_processor -->
1597+
1598+
```python
1599+
class CustomAttributeSpanProcessor(SpanProcessor):
1600+
def __init__(self):
1601+
pass
1602+
1603+
def on_start(self, span: Span, parent_context=None):
1604+
# Add this attribute to all spans
1605+
span.set_attribute("trace_sample.sessionid", "123")
1606+
1607+
# Add another attribute only to create_message spans
1608+
if span.name == "create_message":
1609+
span.set_attribute("trace_sample.message.context", "abc")
1610+
1611+
def on_end(self, span: ReadableSpan):
1612+
# Clean-up logic can be added here if necessary
1613+
pass
1614+
```
1615+
1616+
<!-- END SNIPPET -->
1617+
1618+
Add the span processor to trace provider:
1619+
1620+
<!-- SNIPPET:sample_agents_basics_with_console_tracing_custom_attributes.add_custom_span_processor_to_tracer_provider -->
1621+
1622+
```python
1623+
provider = cast(TracerProvider, trace.get_tracer_provider())
1624+
provider.add_span_processor(CustomAttributeSpanProcessor())
1625+
```
1626+
1627+
<!-- END SNIPPET -->
1628+
1629+
14991630
## Troubleshooting
15001631

15011632
### Logging

0 commit comments

Comments
 (0)