Microsoft Foundry: The Agentic Backplane

Published
Mar 14, 2026
Author
Chris Domino

Introduction

Before getting into this blog post, please review my original seven-part series that introduces “The Easy Way” and “The Hard Way” approaches to integrate Microsoft Foundry with SharePoint. The focus there was on architecture, security, and emerging best practices around allowing agents to reason over your company’s internal data.

However, I never actually went as far as plugging this into a custom app and repositioning Foundry as a separate logical layer in an Azure architecture. We’re all used to the conventional frontend/middleware/backend paradigm for modern cloud systems; this post will detail out how to include Foundry as the agentic backplane: a new, all-encompassing AI tier fully integrated into our systems.

The Agentic Backplane

This (much smaller) blog series instead focuses more on app integration and production readiness (and less on SharePoint) to answer the question: “Okay, I’ve used Foundry and have a working POC…now what?” This first post will discuss layering Foundry into an Azure architecture. Next, I’ll share how to automatically promote agents to new environments. Then in the finale I’ll cover some exciting enhancements I’ve made to “The Hard Way.”

The Agentic Backplane

What excites me the most about Foundry is that it is bringing native AI development “home” to engineers living in the Microsoft ecosystem; I feel like I am getting my curly braces and semicolons back. We cannot only integrate the dozens of APIs under Azure AI Services into our apps easier than ever, but also explore the new Foundry Project endpoints that take interacting with agents in C# to the next level. And if you’re not a Redmond fanboy like me, you’ll appreciate Foundry’s inclusive nature providing Python and JavaScript code samples front and center right alongside of the C#.

All programmers are welcome in Foundry!

Enterprise AI

But it’s about much more than just code; it’s about enterprise AI. Does simply calling a chat completion API mean that your system is part of the LLM revolution? On the one hand…technically, of course…but with the other hand having a firm grasp on Foundry, you’ll quickly learn that it’s much bigger than that.

With Foundry implemented as an Azure resource, we can integrate it into the cloud architectures we’ve been leveraging for years using the tools we’ve been mastering for decades. This means RBAC, model deployments, APIs, observability, and a plethora of other tools built into Foundry can make our agents robust, scalable, and production ready for large scale releases to our users.

By treating Foundry as simply another PaaS component that we can include in our existing resource groups, deploy with our existing Azure CLI scrips, secure with our existing Entra ID configuration, and monitor with our existing telemetry tools, we can do much more than simply implement agentic user stories; we can manage an entire ecosystem of AI infrastructure and naturally layer it into our new or existing apps and let it keep our systems surfing atop the crest of the LLM wave.

In addition to all the enterprise functionality we can leverage in Foundry due to its nature of having been implemented as an Azure resource (versus, for example, something like Copilot Studio which is a standalone tool whose agents can only be deployed to M365), we can also provision Foundry Projects under a single Foundry “Portal” instance and achieve AI tenancy: different models, agents, and tools secured for distinct user populations.

This allows us to plan our agentic infrastructure in way that will scale along with our organizations. AI engineers and end users in different departments can use Foundry’s playground experience and browser tools to create, secure, and test bespoke agents against the latest models specialized for their requirements and grounded in their data. And all of that comes along for the ride as AI developers automatically promote the entire agentic backplane – configured agents together with consumed APIs – up the environmental chain to production as part of a single, cohesive Azure architecture.

Foundry Project API

The “new” Foundry Project experience comes with its own API that allows developers to configure and automate their agentic backplanes as well as interact with agents and workflows. This is what empowers us to do full enterprise AI development leveraging Azure and the .NET framework.

This is a big paradigm shift away from “conventional” C# work in this space, where the focus was on consuming Azure AI Services (f.k.a. Cognitive Services) via API calls. If you needed to do chat completions for example, you’d have to provision an Azure Open AI PaaS resource and then consume its endpoints in your code.

However, leveraging the Foundry Project API changes this to a much more agentic approach. Instead, the code interacts with Foundry agents directly: feeding them user prompts messages and parsing their resulting content. In this scenario, our robots can ostensibly be thought of as functions: single units of logic that convert inputs to outputs.

This change is a nice example of the agentic backplane concept: in this new world, we encapsulate AI logic directly in the agent via its instructions, tools, and other settings. Then when coding against the Foundry Project API, we use this agent as the completions endpoint to create chatbots (in the standard case) or query for data (in more advanced scenarios).

Now if we need to do more “specialized” AI work, such as cracking open a file and enumerating its pages, Document Intelligence would still be the tool of choice. Or if we’re performing custom vectorization, we’d talk to an Azure OpenAI instance. These use cases don’t change as they aren’t part of the Project API, but Foundry still improves upon such scenarios by making all Azure AI services available from the Project’s parent Portal resource.

Foundry Portal & Projects

Our custom logic that consumed one-off Azure AI Services pre-Foundry doesn't change; we simply no longer have to provision separate PaaS components. Now, our agentic backplane has everything we need naturally layered into our architecture. These APIs (keys, versions, etc.) are then centrally managed in one place, vastly simplifying the surface area of our resource groups.

Let’s jump into the code and take a look at a sample method that uses the new Azure.AI.Projects APIs to converse with an agent. Note: null checks, try/catch statements, logging, etc. have been removed for brevity; I will include a link at the end of the post to the GitHub repo hosting the full FoundryService implementation.

1.	using Azure.Core;
2.	using Azure.AI.Projects;
3.	using Azure.AI.Projects.OpenAI;
4.	using Azure.AI.Agents.Persistent;

5.	. . .

6.	public async Task<AgentResponse<string>> ConverseWithAgentAsync(
		string agentName,
		string userMessage,
		string conversationId,
		Uri foundryProjectAPIEndpoint,
		TokenCredential foundryCredential)
7.	{
8.		//initialization
9.		AIProjectClient foundryClient = new AIProjectClient(foundryProjectAPIEndpoint, foundryCredential);
10.		AgentRecord agent = await foundryClient.Agents.GetAgentAsync(agentName);
11.		HashSet<string> annotations = new HashSet<string>();
12.		StringBuilder agentMessage = new StringBuilder();

13.		//get conversation
14.		ProjectConversation conversation = string.IsNullOrWhiteSpace(conversationId)
15.			?
16.				await foundryClient.OpenAI.Conversations.CreateProjectConversationAsync()
17.			:
18.				await foundryClient.OpenAI.Conversations.GetProjectConversationAsync(conversationId);

19.		//send the user's message to the agent
20.		ProjectResponsesClient responseClient = foundryClient.OpenAI.GetProjectResponsesClientForAgent(agent, conversation.Id);
21.		ClientResult<ResponseResult> response = await responseClient.CreateResponseAsync(userMessage);

22.		//get the agent's response
23.		foreach (MessageResponseItem outputItem in response.Value.OutputItems.OfType<MessageResponseItem>())
24.		{
25.			//get each piece of content
26.			foreach (ResponseContentPart content in outputItem.Content)
27.			{
28.				//capture answer
29.				agentMessage.AppendLine(content.Text);

30.				//collect annotations
31.				foreach (ResponseMessageAnnotation annotation in content.OutputTextAnnotations)
32.				{
33.					//only consider URL citations
34.					if (annotation.Kind == ResponseMessageAnnotationKind.UriCitation)
35.						annotations.Add(((UriCitationMessageAnnotation)annotation).Uri.ToString());
36.				}
37.			}
38.		}

39.		//return
40.		return new AgentResponse<string>(agentMessage.ToString().Trim(), conversation.Id, annotations);
41.	}

Starting off on Line #9, we create an AIProjectClient. This is the main entry point to the new API, taking in the URI to your Foundry Project, which is given by the following Bash Azure CLI command…

az cognitiveservices account show --resource-group '<your-resource-group-name>' --name '<your-foundry-name>' --query 'properties.endpoints."AI Foundry API"' --output 'tsv';

…as well as presented front and center on the home page of the PaaS instance…

Developer-centric Foundry Home Page

Then on Line #10, we get the agent by name (which is safe in Foundry, since it enforces uniqueness of this property). The next stanza (Line #’s 13-18) has simple logic that resumes an existing conversation or starts a new one if no id is given. There is no need to worry about memory or persistence here; the Foundry API handles all of that for us; our frontends simply need to maintain a single conversation id string in state.

Line #’s 19-21 then “client hop” to get a ProjectResponsesClient which abstracts OpenAI chat completions and sends the user’s message to the agent in the context of a conversation. Note that in the current beta is pretty slow (more on how to enable preview code compilation shortly) so Line #21 will chug for several seconds.

Next, we process the Agent’s response on Line #’s 22-38, walking through each ResponseContentPart of each MessageResponseItem and accumulating the agent’s answer (Line #29). Note that there are a lot of messages of various types that come back, so the OfType < MessageResponseItem > on Line #23 is a handy trick I use to only get the content we’d want to show to the user. At the end of the stanza is an example of how to pull annotations in case the target agent’s instructions tell it to include them.

Finally, we return the final agent’s response on Line #40. AgentResponse< T > is a simple DTO to handle both text responses (which could be improved to support markdown or even HMTL in a chat bot scenario) or an object (if the agent returns structured JSON in a more data-driven search-based use case).

Preview APIs

I built this using Visual Studio 2026 + .NET 10, which continues the IDE’s behavior of requiring developers to opt in hard to preview APIs. To allow this code to compile, there are three steps you need to follow. First, to get the NuGet packages, you need to search with the “prelease” flag turned on.

Prelease Foundry Project Nuget Packages

Then in any code file using these beta namespaces, we’ll need to include #pragma warning disable OPENAI001 before any calls made against them. Finally, in not only the Visual Studio .csproj containing the code, but also any others consuming it as a project reference throughout the solution up the dependency chain, we need to add the following:

<PropertyGroup>
	<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup> 

This feels like signing a waiver before bungee jumping off a bridge! But I don’t mind; this is an example of Microsoft keeping everything Kosher at the enterprise level by not only giving us beta bits so we can master new technology before it launches, but also adding a layer of protection for production systems against preview functionality.

SharePoint Authentication

In most agentic tool cases, you can impersonate service principals via an Entra ID app that has the permissions below (or a subset, depending on your requirements and adherence to least privileged security principles) against a Foundry instance. To do so, wrap its app id, tenant id, and client secret in a ClientSecretCredential and use that as the second parameter to your AIProjectClientobject’s constructor.

  • Contributor
  • Azure AI User
  • Azure AI Developer
  • Cognitive Services User
  • Cognitive Services Contributor

To achieve this, pull these three with strings from local settings files or preferably Key Vault (especially in higher environments):

return new ClientSecretCredential("<your-tenant-id>", "<your-app-id>", "<your-app-client-secret>"); 

However, this does not work for Foundry agents using “The Easy Way’s” out-of-the-box SharePoint tool (which is still in Preview). Since this grounding needs to run as the current user to perform dynamic content security trimming against site collection data, the API will reject impersonated requests with the following error:

[Sharepoint-tool] Request to Graph API failed with HTTP status 400, error-code: AuthenticationError and error-message: AppOnly OBO tokens not supported by target service.

The SharePoint tool does not support Entra ID "impersonated" security contexts.

As long as the current user has a Copilot license, the SharePoint tool will function properly in the Foundry playground UI (since it’s in the “direct” context of an authenticated browser). However, it needs some additional handling to work in a custom app (because there, users are most likely authenticated via MSAL to Graph or your Entra ID app’s scope, not Foundry).

It might be tempting to instead use a DefaultAzureCredential, but that will only appear to work locally. While this can identify you via your Visual Studio authentication (or Azure CLI login or even your deployed app service’s managed identity when running the cloud), it won’t pick up the current user’s bearer token on the backend.

Instead, we need to configure our ASP.NET Core APIs to support downstream API token acquisition. Here are the salient bits from the Program.cs file hosting our backend: