Have you ever wanted to give your AI assistants access to your own custom tools and data? That's exactly what Model Context Protocol (MCP) allows us to do, and I've been experimenting with it lately.
I read a lot recently about Model Context Protocol (MCP) and how it is changing the way AI interacts with external systems. I was curious to see how it works and how I can use it in my own projects. There are many tutorial available online but one of my favorite was written by James Montemagno Build a Model Context Protocol (MCP) server in C#. This post isn't a tutorial, but rather a summary of my experience and what I learned along the way while building a real MCP server that manages short URLs.
MCP doesn't change AI itself, it's a protocol that helps your AI model to interact with external resources: API, databases, etc. The protocol simplifies the way AI can access an external system, and it allows the AI to discover the available tools from those resources. Recently I was working on a project that manages short URLs, and I thought it would be a great opportunity to build an MCP server that manages short URLs. I wanted to see how easy it is to build and then use it in VSCode with GitHub Copilot Chat.
Code: All the code of this post is available in the branch exp/mcp-server of the AzUrlShortener repo on GitHub.
Setting Up: Adding an MCP Server to a .NET Aspire Solution
The AzUrlShortener is a web solution that uses .NET Aspire, so the first thing I did was create a new project using the command:
dotnet new web -n Cloud5mins.ShortenerTools.MCPServer -o ./mcpserver
Required Dependencies
To transform this into an MCP server, I added these essential NuGet packages:
Microsoft.Extensions.Hosting
ModelContextProtocol.AspNetCore
Since this project is part of a .NET Aspire solution, I also added references to:
- The
ServiceDefaults
project (for consistent service configuration) - The
ShortenerTools.Core
project (where the business logic lives)
Integrating with Aspire
Next, I needed to integrate the MCP server into the AppHost
project, which defines all services in our solution. Here's how I added it to the existing services:
var manAPI = builder.AddProject<Projects.Cloud5mins_ShortenerTools_Api>("api")
.WithReference(strTables)
.WaitFor(strTables)
.WithEnvironment("CustomDomain",customDomain)
.WithEnvironment("DefaultRedirectUrl",defaultRedirectUrl);
builder.AddProject<Projects.Cloud5mins_ShortenerTools_TinyBlazorAdmin>("admin")
.WithExternalHttpEndpoints()
.WithReference(manAPI);
// 👇👇👇 new code for MCP Server
builder.AddProject<Projects.Cloud5mins_ShortenerTools_MCPServer>("mcp")
.WithReference(manAPI)
.WithExternalHttpEndpoints();
Notice how I added the MCP server with a reference to the manAPI
- this is crucial as it needs access to the URL management API.
Configuring the MCP Server
To complete the setup, I needed to configure the dependency injection in the program.cs
file of the MCPServer project. The key part was specifying the BaseAddress of the httpClient:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services.AddMcpServer()
.WithTools<UrlShortenerTool>();
builder.AddServiceDefaults();
builder.Services.AddHttpClient<UrlManagerClient>(client =>
{
client.BaseAddress = new Uri("https+http://api");
});
var app = builder.Build();
app.MapMcp();
app.Run();
That's all that was needed! Thanks to .NET Aspire, integrating the MCP server was straightforward. When you run the solution, the MCP server starts alongside other projects and will be available at http://localhost:{some port}/sse
. The /sse
part of the endpoint means (Server-Sent Events) and is critical - it's the URL that AI assistants will use to discover available tools.
Implementing the MCP Server Tools
Looking at the code above, two key lines make everything work:
builder.Services.AddMcpServer().WithTools<UrlShortenerTool>();
- registers the MCP server and specifies which tools will be availableapp.MapMcp();
- maps the MCP server to the ASP.NET Core pipeline
Defining Tools with Attributes
The UrlShortenerTool
class contains all the methods that will be exposed to AI assistants. Let's examine the ListUrl
method:
[McpServerTool, Description("Provide a list of all short URLs.")]
public List<ShortUrlEntity> ListUrl()
{
var urlList = _urlManager.GetUrls().Result.ToList<ShortUrlEntity>();
return urlList;
}
The [McpServerTool]
attribute marks this method as a tool the AI can use. I prefer keeping tool definitions simple, delegating the actual implementation to the UrlManager
class that's injected in the constructor: UrlShortenerTool(UrlManagerClient urlManager)
.
The URL Manager Client
The UrlManagerClient
follows standard HttpClient patterns. It receives the pre-configured httpClient in its constructor and uses it to communicate with the API:
public class UrlManagerClient(HttpClient httpClient)
{
public async Task<IQueryable<ShortUrlEntity>?> GetUrls()
{
IQueryable<ShortUrlEntity> urlList = null;
try{
using var response = await httpClient.GetAsync("/api/UrlList");
if(response.IsSuccessStatusCode){
var urls = await response.Content.ReadFromJsonAsync<ListResponse>();
urlList = urls!.UrlList.AsQueryable<ShortUrlEntity>();
}
}
catch(Exception ex){
Console.WriteLine(ex.Message);
}
return urlList;
}
// other methods to manage short URLs
}
This separation of concerns keeps the code clean - tools handle the MCP interface, while the client handles the API communication.
Using the MCP Server with GitHub Copilot Chat
Now for the exciting part - connecting your MCP server to GitHub Copilot Chat! This is where you'll see your custom tools in action.
Configuring Copilot to Use Your MCP Server
Once the server is running (either deployed in Azure or locally), follow these steps:
- Open GitHub Copilot Chat in VS Code
- Change the mode to Agent by clicking the dropdown in the chat panel
- Click the Select Tools... button, then Add More Tools
Selecting the Connection Type
GitHub Copilot supports several ways to connect to MCP servers:
There are multiple options available - you could have your server in a container or run it via command line. For our scenario, we'll use HTTP.
Note: At the time of writing this post, I needed to use the HTTP URL of the MCP server rather than HTTPS. You can get this URL from the Aspire dashboard by clicking on the resource and checking the available Endpoints.
After selecting your connection type, Copilot will display the configuration file, which you can modify anytime.
Interacting with Your Custom Tools
Now comes the fun part! You can interact with your MCP server in two ways:
- Natural language queries: Ask questions like "How many short URLs do I have?"
- Direct tool references: Use the pound sign to call specific tools: "With #azShortURL list all URLs"
The azShortURL
is the name we gave to our MCP server in the configuration.
Key Learnings and Future Directions
Building this MCP server for AzUrlShortener taught me several valuable lessons:
What Worked Well
- Integration with .NET Aspire was remarkably straightforward
- The attribute-based approach to defining tools is clean and intuitive
- The separation of tool definitions from implementation logic keeps the code maintainable
Challenges and Considerations
- The csharp-SDK is only a few weeks old and still in preview
- OAuth authentication isn't defined yet (though it's being actively worked on)
- Documentation is present but evolving rapidly as the technology matures, so some features may not be fully documented yet
For the AzUrlShortener project specifically, I'm keeping this MCP server implementation in the experimental branch mcp-server
until I can properly secure it. However, I'm already envisioning numerous other scenarios where MCP servers could add great value.
If you're interested in exploring this technology, I encourage you to:
- Check out the GitHub repo
- Fork it and create your own MCP server
- Experiment with different tools and capabilities
Join the Community
If you have questions or want to share your experiences with others, I invite you to join the Azure AI Community Discord server:
The MCP ecosystem is growing rapidly, and it's an exciting time to be part of this community!
~Frank