# Integrate Microsoft Agent Framework with Microsoft Fabric Core MCP Server

Microsoft Fabric is revolutionizing the data analytics space and is bringing together data integration, data engineering and data analytics under a unified platform. This reduces overall complexities involved maintaining multiple, disconnected tools and services.

Recently, the [Fabric Core MCP Server](https://learn.microsoft.com/en-us/rest/api/fabric/articles/mcp-servers/core-remote/overview-core-mcp-server) was released. At the time of this writing this feature is in preview. So please test it thoroughly before you use it in your production environment.

Fabric Core MCP Server is a remote endpoint that enables AI agents to interact with the Microsoft Fabric ecosystem. This opens a window of opportunity where MAF Agents can seamlessly communicate with artifacts within the Microsoft Fabric Ecosystem which eventually can reduce the complexities involved in overall code and structural customization.

Couple of weeks ago I had published an [article](https://www.azureguru.net/build-ai-agents-with-microsoft-agent-framework-to-access-azure-services-using-entra-oauth) that demonstrated the integration MAF AIAgent with Azure Services. To be honest, there were a lot of nuts and bolts involved in getting this set up running. But leveraging Fabric Core MCP Server you skip all such complexities when it comes to integrating it with Microsoft Fabric.

In this article we will deep dive in how to integrate MAF **AIAgent** with **Fabric MCP Server**.

To get started, we have to setup a few delegated permissions for the service principal that we will use.

The service principal will impersonate the logged in user and based on the user permissions assigned to the user for a specific Fabric item, the AIAgent will interact with the underlying Fabric services.

I granted the following delegated permissions to the service principal that I will use.

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/b4b317b4-f392-485d-a004-d7d0ac065aa6.png align="center")

We will use the usual Fabric scope : **https://api.fabric.microsoft.com/.default** and [**MSAL**](https://learn.microsoft.com/en-us/entra/identity-platform/msal-overview) (Microsoft Authentication Library) for token generation and the Fabric MCP Server endpoint **https://api.fabric.microsoft.com/v1/mcp/core**

### **SetUp**

There are two Entra users

**sachin.nandanwar @** [**azureguru.net**](http://azureguru.net) and **sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net)

User **sachin.nandanwar @** [**azureguru.net**](http://azureguru.net) is an admin on the Fabric tenant while the user **sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net) only has Viewer access on one of the Fabric workspaces called "My Test workspace"

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/8f380e0d-593c-4add-b82d-f70a3b80c4eb.png align="center")

We will test a few prompts that would allow us to interact with the workspace "My Test workspace" on the Fabric tenant.

Following is the list of all the tools available through the Fabric MCP server.

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/febe522e-ad73-4903-b21b-33a18926af59.png align="center")

By a simple prompt, you could list workspaces, create workspaces, create/update/delete items and so and so forth.

Of course the outcome of these actions will be dependent on the level of access the logged in user has for the underlying objects.

As mentioned earlier, there are Entra two users

*   **(Sachin.Nand)** **sachin.nandanwar @** [**azureguru.net**](http://azureguru.net)
    
*   **(Sachin Nandanwar)** **sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net)
    

I will test the prompts by logging in with both users.

### **Code**

Add the following references to a new C# console project

```csharp
dotnet add package Azure;
dotnet add package Azure.Core;
dotnet add package Microsoft.Agents.AI;
dotnet add package Azure.AI.OpenAI;
dotnet add package Microsoft.Extensions.AI;
dotnet add package ModelContextProtocol.Client;
dotnet add package Microsoft.Identity.Client;
dotnet add package Microsoft.Extensions.DependencyInjection;
```

Declare a bunch of variables in **Program.cs**

```csharp
private static string RedirectURI = "http://localhost";
private static string clientId = "Service Principal Client Id";
private static string tenantId = "Fabric tenant Id";
private static readonly HttpClient client = new HttpClient();
private static string[] scopes = new string[] { "https://api.fabric.microsoft.com/.default" };
private static string Authority = $"https://login.microsoftonline.com/{tenantId}";
public static HttpClient Client => client;
```

Next , define an **Authentication** method that validates the user sign-in and delegated scopes using Microsoft Entra ID and returns [AuthenticationResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.identity.client.authenticationresult?view=msal-dotnet-latest).

**ReturnAuthenticationResult >>**

```csharp
public async static Task <AuthenticationResult> ReturnAuthenticationResult() {
  string AccessToken;
  PublicClientApplicationBuilder PublicClientAppBuilder =
    PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(Authority)
    .WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
    .WithRedirectUri(RedirectURI);

  IPublicClientApplication PublicClientApplication = PublicClientAppBuilder.Build();
  var accounts = await PublicClientApplication.GetAccountsAsync();
  AuthenticationResult result;
  try {

    result = await PublicClientApplication.AcquireTokenSilent(scopes, accounts.First())
      .ExecuteAsync()
      .ConfigureAwait(false);
  } catch {
    result = await PublicClientApplication.AcquireTokenInteractive(scopes)
      .ExecuteAsync()
      .ConfigureAwait(false);

  }
  return result;
}
```

Add the following code in **Program.cs** to read settings from the config file **appsettings.json**

```csharp
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.Build();
```

**Read credentials and register** **Chatclient and return a ChatClientAgent**

```csharp
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

var credential = new AzureKeyCredential(configuration["AppSettings:ApiKey"]);

servicecollection.AddKeyedChatClient(
    "ChatClient",
    (
        sp =>
            new AzureOpenAIClient(new Uri(configuration["AppSettings:EndPoint"]), credential)
                .GetChatClient(configuration["AppSettings:Chat_DeploymentName"])
   .AsIChatClient()
    )
);

builder.Services.AddSingleton<ChatClientAgent>(sp =>
{
    return new ChatClientAgent(sp.GetKeyedService<IChatClient>("ChatClient"));
});
```

Now create a DI container to the **ChatClientAgent**

```csharp
ServiceProvider serviceprovider = servicecollection.BuildServiceProvider();

var chatlient = serviceprovider.GetServices<ChatClientAgent>();

List<ChatClientAgent> lstchatclient = new(chatlient);
```

Create a client function that connects to the MCP endpoints and returns the MCP Server tool list.

```csharp
      public static async Task < List < McpClientTool >> ConnectMCP() {
      AuthenticationResult result = await ReturnAuthenticationResult();

      var httpClient = new HttpClient {
        Timeout = Timeout.InfiniteTimeSpan
      };
      var transport = new ModelContextProtocol.Client.HttpClientTransport(
        new HttpClientTransportOptions {
          Endpoint = new Uri("https://api.fabric.microsoft.com/v1/mcp/core"),
            Name = "MCP Client",
            TransportMode = HttpTransportMode.AutoDetect,
            EnableStandaloneGetStream = false,
            AdditionalHeaders = new Dictionary < string, string > {
              {
                "Authorization",
                $ "Bearer {result.AccessToken}"
              }
            }
        },
        httpClient
      );

      var mcpClient = await McpClient.CreateAsync(transport);
      var tools = await mcpClient.ListToolsAsync();
      return tools.ToList();
    }
```

In the above code, we connect to MCP server endpoint through the MCP **HttpClientTransport** class and pass the bearer token through the method **ReturnAuthenticationResult** which returns an [**AuthenticationResult**](https://learn.microsoft.com/en-us/dotnet/api/microsoft.identity.client.authenticationresult?view=msal-dotnet-latest) object.

Now, configure the **ChatClientAgentOptions** and set its **Tools** property to the method **ConnectMCP()** that was defined above.

```csharp
  var options = new ChatClientAgentOptions()
  {
      ChatOptions = new ChatOptions()
      {
          Instructions = "You are a Fabric Agent and you execute the appropriate tools",
          ToolMode = AutoChatToolMode.Auto,
          Tools = [.. await ConnectMCP()]
      },
      Name = "Fabric Agent"
  };
```

Next, assign the options configured above to the **ChatClient**, create an **AIAgent** from it and then send a prompt to the agent.

```csharp
var agent = lstchatclient [0].ChatClient.AsAIAgent(options);

AgentResponse  agentresponse = await agent.RunAsync("Create a lakehouse with name Fabric_MCP_LakeHouse in workspace My Test Workspace.");

Console.Write(agentresponse.Text);
```

Logging in as **sachin.nandanwar @** [**azureguru.net**](http://azureguru.net) and the lakehouse creation succeeds

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/8c6c5a92-c97e-4506-abd7-17564d478c2e.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/f0eb3835-1203-42cc-8554-49451c3ceead.png align="left")

Trying to do the same logging in as **sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net)

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/694a0f5a-4050-464d-81a1-5d7143ced7d1.png align="center")

This is because **sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net) only has Viewer access for the workspace "My Test Workspace".

Now let me try to list items(semantic models) in the same workspace. The prompt should return list of the semantic models as the user (**sachin\_nandanwar @** [**azureguru.net**](http://azureguru.net) ) has viewer access for the workspace.

The updated prompt is

```csharp
AgentResponse  agentresponse = await agent.RunAsync("Provide a list of semantic models in My Test Workspace.");

Console.Write(agentresponse.Text);
```

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/88a424f5-dc6e-4672-b3a9-841d532dbdf9.png align="center")

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/3af5993f-919b-4de0-9dd9-5b1fbd8d674a.png align="left")

There are many amazing things that you could do using the Fabric MCP Server tools, of course being limited to the underlying permissions the logged in user has.

But you might argue that all these features are already available through **VS Code GitHub Copilot**.

Yes it is, but what if you want to extend this functionality to other external applications or AI agents ?

This is where exposing your agent through **MCP** becomes particularly useful. Instead of limiting the functionality to a specific environment you can now make your agent available as an MCP tool for Fabric ecosystem that can be consumed by any MCP-compatible client.

### Execution

![](https://cdn.hashnode.com/uploads/covers/6693c62c166ee9c594cffda0/7740ce2d-a78e-48b5-8478-584d86f2d1c9.gif align="center")

### Conclusion

Integrating the **Microsoft Agent Framework (MAF)** with the **Fabric Core MCP Server** provides a powerful way to extend AI agents with Fabric capabilities.

Through this article I tried to demonstrates how **MAF and MCP** can work together to connect AI agents with external data and services while maintaining authentication and integrating the Fabric security model.

Thanks for reading !!!
