In earlier posts in this series, we’ve explored how to extend AI agents using function tools, how to compose agents together as function tools, and how to build and debug MCP servers in .NET.
In this post, we look at how you can take an existing AI agent built with the Microsoft Agent Framework and expose it as an MCP tool, thereby making it available to any MCP-compatible client.
This is where the two worlds collide.
- We already know how to build agents.
- We already know how to build MCP servers.
Now we combine them.
The idea is simple: take an agent, convert it to a function, wrap it as an MCP tool, and serve it over HTTP.
In this blog post, we cover the following:
- What it means to expose an agent as an MCP tool
- Why you would want to do this
- The key NuGet packages required
- How to create an AI agent using direct OpenAI
- How to convert that agent to an MCP tool
- How to host the MCP server with SSE transport
- Testing with MCP Inspector
Source code and video demo is included.
Let’s dig in.
~
What Does It Mean to Expose an Agent as an MCP Tool
In the agents as function tools post, we saw how an agent can be converted to an AIFunction using the .AsAIFunction() method.
This allows one agent to call another agent as if it were a regular function tool.
The Model Context Protocol takes this a step further. Instead of one agent calling another agent internally, we expose that agent-as-function to the outside world via an MCP server.
Any MCP-compatible client — VS Code, Claude Desktop, MCP Inspector, or your own custom client — can discover and invoke the agent.
The conversion chain looks like this:
AI Agent → AIFunction → McpServerTool → MCP Server
The agent’s name becomes the tool name. The agent’s description becomes the tool description. MCP clients see it as just another tool, they don’t need to know there’s an entire AI agent behind it.
~
Why Expose an Agent as an MCP Tool
There are several reasons you might want to do this:
- Reusability — an agent you’ve already built and tested can be consumed by any MCP-compatible client without writing new integration code
- Standardised access — MCP provides a well-defined protocol so you build once and connect everywhere
- Composability — other agents or tools can discover and call your agent through MCP, enabling multi-agent workflows across different systems
- Separation of concerns — the agent logic lives in your server, and clients simply invoke it over the wire
If you’ve been following this series, you’ll recognise the pattern.
In the function tools post, we gave agents the ability to call functions.
In the agents as function tools post, we let agents call other agents.
Now we’re letting anything call our agent -as long as it speaks MCP.
~
Setting Up the Project
The project uses the ASP.NET Core Web SDK since we’re hosting the MCP server over HTTP with SSE transport.
Here’s the project file with the required NuGet packages:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Agents.AI" Version="1.0.0-preview.260205.1" /> <PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.0.0-preview.260205.1" /> <PackageReference Include="ModelContextProtocol" Version="0.8.0-preview.1" /> <PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.8.0-preview.1" /> <PackageReference Include="OpenAI" Version="2.8.0" /> <PackageReference Include="System.ClientModel" Version="1.8.1" /> </ItemGroup> </Project>
The key packages to note:
- Microsoft.Agents.AI and Microsoft.Agents.AI.OpenAI — the Microsoft Agent Framework and its OpenAI integration
- ModelContextProtocol and ModelContextProtocol.AspNetCore — the .NET MCP SDK with ASP.NET Core SSE transport support
- OpenAI — the official OpenAI .NET SDK for direct API access
~
The Agent We’re Exposing
For this example, we’re using a nutrition agent that searches for high protein recipes.
If you’ve been following the series, you’ll recognise this from the agents as function tools post where it was used as a sub-agent within our Iron Mind AI personal trainer.
The agent has a single function tool SearchRecipesAsync . This takes a search term, a minimum protein threshold, and a maximum number of results:
public class NutritionAgent
{
[Description("Searches for high protein recipes optimized for strength training. " +
"Returns recipes with detailed nutrition information. " +
"Best for finding recipes for 5x5 training, muscle building, or post-workout meals.")]
public static Task<List<string>> SearchRecipesAsync(
[Description("Search term (e.g., 'chicken', 'beef', 'protein', 'breakfast')")] string searchTerm,
[Description("Minimum protein grams per serving (default 20)")] int minProtein = 20,
[Description("Maximum number of recipes to return (default 3)")] int maxResults = 3)
{
var results = _stubRecipes
.Where(r => r.Title.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) ||
r.Ingredients.Any(i => i.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)))
.Where(r => r.Nutrition != null && r.Nutrition.ProteinGrams >= minProtein)
.Take(maxResults)
.Select(r => JsonSerializer.Serialize(r))
.ToList();
return Task.FromResult(results);
}
}
The [Description] attributes are crucial here. They tell the AI agent (and ultimately the MCP client) what the function does and what each parameter means. This is the same pattern we covered in the function tools post.
Each recipe is a simple model with nutritional information:
public class Recipe
{
public string Title { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public List<string> Ingredients { get; set; } = new();
public List<string> Instructions { get; set; } = new();
public NutritionInfo? Nutrition { get; set; }
public string PrepTime { get; set; } = string.Empty;
public string CookTime { get; set; } = string.Empty;
public int Servings { get; set; }
}
We also have a NutrionInfo class :
public class NutritionInfo
{
public int Calories { get; set; }
public int ProteinGrams { get; set; }
public int CarbsGrams { get; set; }
public int FatGrams { get; set; }
}
~
Creating the Agent and Exposing It as an MCP Tool
This is where it all comes together. The Program.cs file does three things:
- Creates an AI agent using direct OpenAI
- Converts the agent to an MCP tool
- Hosts the MCP server with SSE transport
Here’s the full code:
using Agent_Framework_7_Existin_Agent_as_MCP_Tool.Agent; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; using ModelContextProtocol.AspNetCore; using ModelContextProtocol.Server; using OpenAI; string apiKey = "your-openai-api-key"; string model = "gpt-4o-mini"; // Create the nutrition agent using direct OpenAI AIAgent nutritionAgent = new OpenAIClient(apiKey) .GetChatClient(model) .AsIChatClient() .AsAIAgent( instructions: "You can fetch recipes and nutrition data.", name: "NutritionAgent", description: "An agent that searches for high protein recipes and nutrition information.", tools: [AIFunctionFactory.Create(NutritionAgent.SearchRecipesAsync)] ); // Convert the agent to an AIFunction and then to an MCP tool. // The agent name and description will be used as the MCP tool name and description. McpServerTool tool = McpServerTool.Create(nutritionAgent.AsAIFunction()); // Register the MCP server with SSE transport and expose the tool via the server. var builder = WebApplication.CreateBuilder(args); builder.Services .AddMcpServer() .WithHttpTransport() .WithTools([tool]); var app = builder.Build(); app.MapMcp(); await app.RunAsync();
Let’s walk through each part.
~
Creating the Agent
We create an OpenAIClient with our API key, get a chat client for the model, and then use the .AsIChatClient().AsAIAgent() extension method chain to create an AIAgent.
This is the same pattern from earlier posts in the series, but note two things:
- We use
.AsIChatClient()before.AsAIAgent(). - We provide a
descriptionparameter. This is important because it becomes the MCP tool description that clients will see.
Next, we will create the MCP tool from the agent.
~
Converting to an MCP Tool
This is the key line:
McpServerTool tool = McpServerTool.Create(nutritionAgent.AsAIFunction());
Two things happen here.
First, .AsAIFunction() converts the entire agent , including its instructions, tools, and conversation handling, into a single callable function. We used this same method in the agents as function tools post to let one agent call another.
Second, McpServerTool.Create() wraps that function as an MCP tool that can be served to clients.
~
Hosting the MCP Server
We use WebApplication.CreateBuilder and the ModelContextProtocol.AspNetCore package to host the MCP server with HTTP/SSE transport.
The three key calls are:
- .AddMcpServer() – registers the MCP server services
- .WithHttpTransport() – configures SSE transport over HTTP
- .WithTools([tool]) – registers our agent-as-MCP-tool
Finally, app.MapMcp() maps the MCP endpoints and app.RunAsync() starts the server.
By default, the server runs on http://localhost:5000.
~
Testing with MCP Inspector
MCP Inspector is a handy tool for testing MCP servers. You can use it to connect to your server, discover tools, and invoke them.
Step 1: Run the project:
dotnet run

Step 2: Open MCP Inspector and configure the connection:
- Transport Type: SSE
- URL: http://localhost:5000/sse

Step 3: Click Connect. You should see the NutritionAgent tool listed with its description.

Step 4: Select the tool and provide a search term (e.g., “chicken“). Click Run Tool:

The MCP Inspector sends the request to your server. Your server invokes the AI agent, which uses its SearchRecipesAsync function tool to find matching recipes. The results are returned to the MCP Inspector as the tool response.

What’s happening behind the scenes is worth highlighting.
The MCP client sends a tools/call request. Your MCP server receives it and invokes the McpServerTool.
The tool calls the AIFunction, which runs the full AI agent. The agent processes the request using its instructions and function tools, and the result flows back through the chain to the MCP client.
~
Demo
You can see this in action in the 5 minute demo:
~
Summary
In this post, we’ve covered how to take an existing AI agent built with the Microsoft Agent Framework and expose it as an MCP tool.
The key part is that the conversion chain :
Agent → AIFunction → McpServerTool
This bridges two powerful concepts we’ve explored separately in this series.
The important pieces to remember:
.AsAIFunction()converts an agent into a callable functionMcpServerTool.Create()wraps that function as an MCP tool.WithHttpTransport()serves the tool over HTTP with SSE transport- The agent’s
nameanddescriptionbecome the MCP tool’s name and description - Any MCP compatible client can discover and invoke the agent
Being able to take an agent you’ve already built and make it available over a standardised protocol is a practical step forward. You build the agent once, and any MCP client can use it.
~
Further Reading and Resources
Some additional resources you might find helpful.
- Model Context Protocol Specification
- Microsoft Agent Framework GitHub Repository
- MCP Inspector
- ModelContextProtocol .NET SDK
- Building and Debugging Your First MCP Server in .NET
- Using Agents as Function Tools
~
Enjoy what you’ve read, have questions about this content, or would like to see another topic?
Drop me a note below.
You can schedule a call using my Calendly link to discuss consulting and development services.
~




