Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
<RootNamespace>SimpleInvocationsAgentClient</RootNamespace>
<AssemblyName>simple-invocations-agent-client</AssemblyName>
<NoWarn>$(NoWarn);NU1903;NU1605</NoWarn>
<NoWarn>$(NoWarn);NU1605</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A hosted agent demonstrating **two layers of MCP (Model Context Protocol) tool integration**:

1. **Client-side MCP (GitHub)** — The agent connects directly to the GitHub MCP server via `McpClient`, discovers tools, and handles tool invocations locally within the agent process.
1. **Client-side MCP (Microsoft Learn)** — The agent connects directly to the Microsoft Learn MCP server via `McpClient`, discovers tools, and handles tool invocations locally within the agent process.

2. **Server-side MCP (Microsoft Learn)** — The agent declares a `HostedMcpServerTool` which delegates tool discovery and invocation to the LLM provider (Azure OpenAI Responses API). The provider calls the MCP server on behalf of the agent with no local connection needed.

Expand All @@ -12,16 +12,15 @@ A hosted agent demonstrating **two layers of MCP (Model Context Protocol) tool i
|---|---|---|
| **Connection** | Agent connects to MCP server directly | LLM provider connects to MCP server |
| **Tool invocation** | Handled by the agent process | Handled by the Responses API |
| **Auth** | Agent manages credentials (e.g., GitHub PAT) | Provider manages credentials |
| **Auth** | Agent manages credentials | Provider manages credentials |
| **Use case** | Custom/private MCP servers, fine-grained control | Public MCP servers, simpler setup |
| **Example** | GitHub (`McpClient` + `HttpClientTransport`) | Microsoft Learn (`HostedMcpServerTool`) |
| **Example** | Microsoft Learn (`McpClient` + `HttpClientTransport`) | Microsoft Learn (`HostedMcpServerTool`) |

## Prerequisites

- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
- An Azure AI Foundry project with a deployed model (e.g., `gpt-4o`)
- Azure CLI logged in (`az login`)
- A **GitHub Personal Access Token** (create at https://github.com/settings/tokens)

## Configuration

Expand All @@ -36,7 +35,6 @@ Edit `.env`:
```env
AZURE_AI_PROJECT_ENDPOINT=https://<your-account>.services.ai.azure.com/api/projects/<your-project>
AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o
GITHUB_PAT=ghp_your_token_here
```

## Running directly (contributors)
Expand Down Expand Up @@ -75,7 +73,6 @@ export AZURE_BEARER_TOKEN=$(az account get-access-token --resource https://ai.az

docker run --rm -p 8088:8088 \
-e AGENT_NAME=mcp-tools \
-e GITHUB_PAT=$GITHUB_PAT \
-e AZURE_BEARER_TOKEN=$AZURE_BEARER_TOKEN \
--env-file .env \
hosted-mcp-tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<RootNamespace>HostedWorkflowHandoff</RootNamespace>
<AssemblyName>HostedWorkflowHandoff</AssemblyName>
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
<NoWarn>$(NoWarn);NU1903;NU1605;MAAIW001</NoWarn>
<NoWarn>$(NoWarn);NU1605;MAAIW001</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8088
ENV ASPNETCORE_URLS=http://+:8088
ENTRYPOINT ["dotnet", "HostedWorkflows.dll"]
ENTRYPOINT ["dotnet", "HostedWorkflowSimple.dll"]
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o

```bash
cd dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Workflow-Simple
AGENT_NAME=hosted-workflows dotnet run
AGENT_NAME=hosted-workflow-simple dotnet run
```

The agent will start on `http://localhost:8088`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/microsoft/AgentSchema/refs/heads/main/schemas/v1.0/ContainerAgent.yaml
kind: hosted
name: hosted-workflows
name: hosted-workflow-simple
protocols:
- protocol: responses
version: 1.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
<RootNamespace>SimpleAgentClient</RootNamespace>
<AssemblyName>simple-agent-client</AssemblyName>
<NoWarn>$(NoWarn);NU1903;NU1605;OPENAI001</NoWarn>
<NoWarn>$(NoWarn);NU1605;OPENAI001</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ public override async IAsyncEnumerable<ResponseStreamEvent> CreateAsync(
var sessionStore = this.ResolveSessionStore(request);

// 2. Load or create a new session from the interaction
var sessionConversationId = request.GetConversationId() ?? Guid.NewGuid().ToString();
var sessionConversationId = request.GetConversationId();

var chatClientAgent = agent.GetService<ChatClientAgent>();

AgentSession? session = !string.IsNullOrEmpty(sessionConversationId)
AgentSession? session = !string.IsNullOrWhiteSpace(sessionConversationId)
? await sessionStore.GetSessionAsync(agent, sessionConversationId, cancellationToken).ConfigureAwait(false)
: chatClientAgent is not null
? await chatClientAgent.CreateSessionAsync(sessionConversationId, cancellationToken).ConfigureAwait(false)
? await chatClientAgent.CreateSessionAsync(cancellationToken).ConfigureAwait(false)
: await agent.CreateSessionAsync(cancellationToken).ConfigureAwait(false);

// 3. Create the SDK event stream builder
Expand Down Expand Up @@ -273,7 +273,7 @@ public override async IAsyncEnumerable<ResponseStreamEvent> CreateAsync(
await enumerator.DisposeAsync().ConfigureAwait(false);

// Persist session after streaming completes (successful or not)
if (session is not null && !string.IsNullOrEmpty(sessionConversationId))
if (session is not null && !string.IsNullOrWhiteSpace(sessionConversationId))
{
await sessionStore.SaveSessionAsync(agent, sessionConversationId, session, CancellationToken.None).ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<IsReleased>true</IsReleased>
<InjectSharedThrow>true</InjectSharedThrow>
<NoWarn>$(NoWarn);OPENAI001;MEAI001;NU1903</NoWarn>
<NoWarn>$(NoWarn);OPENAI001;MEAI001;NU1903</NoWarn> <!-- NU1903: Microsoft.Bcl.Memory 9.0.4 transitive vulnerability via Azure SDK; awaiting upstream fix -->
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
<NoWarn>$(NoWarn);NU1903;NU1605</NoWarn>
<NoWarn>$(NoWarn);NU1605</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down